C # Terminazione thread e Thread.Abort ()


85

In MSDN, la descrizione del metodo Thread.Abort () dice: "La chiamata a questo metodo in genere termina il thread."

Perché non SEMPRE?

In quali casi non termina il thread?

Esistono altre possibilità per terminare i thread?

Risposte:


60

Thread.Abort()inietta una ThreadAbortExceptionsul thread. Il thread può annullare la richiesta chiamando Thread.ResetAbort(). Inoltre, ci sono alcune parti di codice, come il finallyblocco che verrà eseguito prima che l'eccezione venga gestita. Se per qualche motivo il thread è bloccato in un tale blocco, l'eccezione non verrà mai sollevata sul thread.

Poiché il chiamante ha pochissimo controllo sullo stato del thread durante la chiamata Abort(), in genere non è consigliabile farlo. Passa invece un messaggio al thread che richiede la terminazione.


Che tipo di messaggio? Intendi una invocazione di metodo?
user101375

4
Dipende da come passi i dati tra i tuoi thread. Ad esempio, se il thread è un thread di lavoro con una coda di attività, è possibile accodare un messaggio PleaseTerminate e lasciare che il thread lo gestisca correttamente.
Brian Rasmussen

Il mio thread ha un grosso problema che deve essere risolto, se non c'è coda di attività.
user101375

Come ho detto, dipende da come è progettato il codice del thread. Forse allora potresti segnalare tramite una variabile membro. È difficile essere più specifici senza il codice effettivo disponibile.
Brian Rasmussen

54

In quali casi non termina il thread?

Questa domanda è un duplicato.

Cosa c'è di sbagliato nell'usare Thread.Abort ()

Esistono altre possibilità per terminare i thread?

Sì. Il tuo problema è che non dovresti mai avviare un thread che non puoi dire educatamente di interrompere e si interrompe in modo tempestivo. Se ti trovi in ​​una situazione in cui devi avviare un thread che potrebbe essere (1) difficile da fermare, (2) bug o peggio di tutto (3) ostile all'utente, allora la cosa giusta da fare è fare un nuovo processo, avviare il thread nel nuovo processo e quindi terminare il processo quando si desidera che il thread si interrompa. L'unica cosa che può garantire la terminazione sicura di un thread non collaborativo è il sistema operativo che interrompe l'intero processo.

Vedi la mia risposta eccessivamente lunga a questa domanda per maggiori dettagli:

Utilizzo dell'istruzione lock all'interno di un ciclo in C #

Il bit rilevante è il bit alla fine in cui discuto quali sono le considerazioni su quanto tempo dovresti aspettare che un thread si uccida prima di interromperlo.


Eric, come dovrei dire educatamente a un thread di fermarsi se quel thread è in attesa di un oggetto di sincronizzazione, ad esempio EventWaitHandle.WaitOne () ;?
Corvin

5
@Corvin: il contratto tra due thread che descrive come un thread deve comunicare con un altro spetta agli autori del codice che gira su quei thread. Se hai requisiti che (1) un thread X deve attendere su un oggetto potenzialmente per sempre, e (2) quel thread Y deve essere in grado di chiudere in modo pulito il thread X in un periodo di tempo finito, allora penso che tu abbia requisiti contraddittori; decidere quale vince. Nel primo caso, il thread Y dovrà attendere. In quest'ultimo caso, il thread X non dovrebbe essere in attesa per sempre, dovrebbe attendere un po 'di tempo.
Eric Lippert

Grazie per aver risposto. Considera la seguente architettura: ho un'applicazione che deve minimizzarsi quando si verifica un determinato evento a livello di sistema. Ho un thread in quell'applicazione che attende un evento denominato globale e fa il suo lavoro quando quell'evento è impostato. Dall'altro lato, la mia applicazione potrebbe dover chiudere prima che si verifichi l'evento, dovendo chiudere quel thread in attesa. Qual è il modo dei samurai di codificare una cosa del genere?
Corvin

@ Corvin: potresti avere un ciclo che attende (con un breve timeout) per l'evento, quindi controlla se deve smettere di provare ad aspettare (in modo che possa uscire normalmente). In questo modo, puoi segnalare al tuo thread che dovrebbe fermarsi e dovresti solo aspettare fino a quando il tuo timeout si ferma.
Kevin Kibler

2
@ Corvin, se rendi quel thread in attesa un thread in background, non dovresti chiuderlo prima che l'applicazione si chiuda.
Don Kirkby

17

Perché non SEMPRE? In quali casi non termina il thread?

Per i principianti, un thread può catturare un ThreadAbortExceptione annullare la propria terminazione. Oppure potrebbe eseguire un calcolo che richiede un'eternità mentre stai cercando di interromperlo. Per questo motivo, il runtime non può garantire che il thread terminerà sempre dopo che lo hai chiesto.

ThreadAbortException ha di più:

Quando viene effettuata una chiamata al metodo Abort per eliminare un thread, Common Language Runtime genera un'eccezione ThreadAbortException. ThreadAbortException è un'eccezione speciale che può essere catturata, ma verrà automaticamente sollevata di nuovo alla fine del blocco catch. Quando viene sollevata questa eccezione, il runtime esegue tutti i blocchi finalmente prima di terminare il thread. Poiché il thread può eseguire un calcolo illimitato nei blocchi finalmente o chiamare Thread.ResetAbort()per annullare l'interruzione, non vi è alcuna garanzia che il thread finirà mai.

Non è necessario Abort()un thread manualmente. Il CLR farà tutto il lavoro sporco per te se lasci semplicemente che il metodo nel thread ritorni; che terminerà il thread normalmente.


Ho bisogno di Abort (), a causa di un ciclo di messaggi avviato su quel thread (Dispatcher.Run ();). Se lo capisco correttamente, devo richiamare un metodo che chiama return nel thread per finirlo?
user101375

7

FileStream.Read()a una named pipe che attualmente non sta ricevendo nulla (leggi i blocchi di chiamate in attesa dei dati in arrivo) non risponderà Thread.Abort(). Rimane dentro la Read()chiamata.


6

Cosa succede se un thread tiene un lucchetto e viene interrotto / ucciso? Le risorse rimangono bloccate

Funziona bene quando quando un thread chiama interrompe se stesso ma non da un altro thread. Interrompi, termina forzatamente il thread interessato anche se non ha completato la sua attività e non fornisce alcuna opportunità per la pulizia delle risorse

riferimento MSDN


vedere: Best practice per il threading gestito


5

Non riesco a interrompere un thread bloccato in un ciclo:

//immortal
Thread th1 = new Thread(() => { while (true) {}});

Posso comunque interrompere il thread se dorme durante il ciclo:

//mortal
Thread th2 = new Thread(() => { while (true) { Thread.Sleep(1000); }});

1
questo non sembra essere vero, ho eseguito un programma di test: `{var th = new Thread (() => {int i = 0; try {while (true) {i ++;}} catch (Exception e) { Console.WriteLine ("aborting @ {0}", i);}}); th.Start (); Thread.Sleep (1000); th.Abort (); th.Join (); }
Weipeng L


3

Perché puoi catturare il ThreadAbortExceptione chiamare Thread.ResetAbortall'interno del gestore.


0

OT: Per un approccio completo, indipendente dalla lingua, discutibilmente utile e dannatamente divertente sulla concorrenza, vedi Verity Stob !


-1

Ho avuto casi in cui il thread era troppo occupato per ascoltare la chiamata Abort (), che di solito si traduce in un'eccezione ThreadAbortingException lanciata al mio codice.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.