C # Thread Termination und Thread.Abort ()

85

In MSDN heißt es in der Beschreibung der Thread.Abort () -Methode: "Diese Methode wird normalerweise aufgerufen der Thread beendet."

Warum nicht IMMER?

In welchen Fällen wird der Thread nicht beendet?

Gibt es eine andere Möglichkeit, Threads zu beenden?

user101375
quelle

Antworten:

60

Thread.Abort()spritzt ein ThreadAbortExceptionauf den Faden. Der Thread kann die Anforderung durch Aufrufen abbrechen Thread.ResetAbort(). Es gibt auch bestimmte Codeteile, wie zfinally Block, der ausgeführt wird, bevor die Ausnahme behandelt wird. Wenn der Thread aus irgendeinem Grund in einem solchen Block steckt, wird die Ausnahme für den Thread niemals ausgelöst.

Da der Aufrufer beim Aufrufen nur sehr wenig Kontrolle über den Status des Threads hat Abort(), ist dies im Allgemeinen nicht ratsam. Übergeben Sie stattdessen eine Nachricht an den Thread, in der Sie die Beendigung anfordern.

Brian Rasmussen
quelle
Was für eine Nachricht? Meinen Sie einen Methodenaufruf?
user101375
4
Das hängt davon ab, wie Sie Daten zwischen Ihren Threads übertragen. Wenn es sich bei Ihrem Thread beispielsweise um einen Arbeitsthread mit einer Aufgabenwarteschlange handelt, können Sie eine PleaseTerminate-Nachricht in die Warteschlange stellen und den Thread ordnungsgemäß damit umgehen lassen.
Brian Rasmussen
Mein Thread hat ein großes Problem, dass Mast gelöst werden muss, wo keine Task-Warteschlange ist.
user101375
Wie gesagt, es hängt davon ab, wie Ihr Thread-Code aufgebaut ist. Vielleicht könnten Sie dann über eine Mitgliedsvariable signalisieren. Ohne den tatsächlich verfügbaren Code ist es schwierig, genauer zu sein.
Brian Rasmussen
54

In welchen Fällen wird der Thread nicht beendet?

Diese Frage ist ein Duplikat.

Was ist falsch an der Verwendung von Thread.Abort ()

Gibt es eine andere Möglichkeit, Threads zu beenden?

Ja. Ihr Problem ist, dass Sie niemals einen Thread starten sollten, von dem Sie nicht höflich sagen können, dass er aufhören soll, und er stoppt rechtzeitig. Wenn Sie sich in einer Situation befinden, in der Sie einen Thread starten müssen, der (1) schwer zu stoppen, (2) fehlerhaft oder am schlimmsten (3) benutzerfeindlich ist, ist es das Richtige, ihn zu erstellen Starten Sie in einem neuen Prozess den Thread im neuen Prozess und beenden Sie den Prozess, wenn der Thread ausfallen soll. Das einzige, was die sichere Beendigung eines nicht kooperativen Threads gewährleisten kann, ist, dass das Betriebssystem seinen gesamten Prozess herunterfährt.

Weitere Einzelheiten finden Sie in meiner übermäßig langen Antwort auf diese Frage:

Verwenden der lock-Anweisung innerhalb einer Schleife in C #

Das relevante Bit ist das Bit am Ende, in dem ich die Überlegungen dazu diskutiere, wie lange Sie warten sollten, bis sich ein Thread selbst beendet, bevor Sie ihn abbrechen.

Eric Lippert
quelle
Eric, wie soll ich einem Thread höflich sagen, dass er anhalten soll, wenn dieser Thread auf ein Synchronisationsobjekt wartet, z. B. EventWaitHandle.WaitOne ();?
Corvin
5
@Corvin: Der Vertrag zwischen zwei Threads, der beschreibt, wie ein Thread mit einem anderen kommunizieren soll, liegt bei den Autoren des Codes, der auf diesen Threads ausgeführt wird. Wenn Sie Anforderungen haben, dass (1) ein Thread X möglicherweise für immer auf ein Objekt warten muss und (2) dieser Thread Y in der Lage sein muss, Thread X in einer begrenzten Zeitspanne sauber herunterzufahren, dann haben Sie meiner Meinung nach widersprüchliche Anforderungen; Entscheide, welcher gewinnt. Wenn erstere, muss Thread Y warten. Wenn letzteres der Fall ist, sollte Thread X nicht ewig warten, sondern einige Zeit warten.
Eric Lippert
Danke für die Antwort. Betrachten Sie die folgende Architektur: Ich habe eine Anwendung, die sich selbst minimieren muss, wenn ein bestimmtes systemweites Ereignis eintritt. Ich habe einen Thread in dieser Anwendung, der auf ein global benanntes Ereignis wartet und seine Arbeit erledigt, wenn dieses Ereignis festgelegt ist. Auf der anderen Seite muss meine Anwendung möglicherweise beendet werden, bevor das Ereignis eintritt, und muss diesen wartenden Thread schließen. Was ist der Samurai-Weg, um so etwas zu codieren?
Corvin
@Corvin: Sie könnten eine Schleife haben, die (mit einer kurzen Zeitüberschreitung) auf das Ereignis wartet und dann prüft, ob es aufhören soll zu warten (damit es normal beendet werden kann). Auf diese Weise können Sie Ihrem Thread signalisieren, dass er gestoppt werden soll, und Sie sollten nur so lange warten müssen, bis das Timeout beendet ist.
Kevin Kibler
2
@Corvin, wenn Sie diesen wartenden Thread zu einem Hintergrund-Thread machen, sollten Sie ihn nicht schließen müssen, bevor die Anwendung beendet wird.
Don Kirkby
17

Warum nicht IMMER? In welchen Fällen wird der Thread nicht beendet?

Für den Anfang kann ein Thread eine fangen ThreadAbortExceptionund seine eigene Beendigung abbrechen. Oder es könnte eine Berechnung durchführen, die ewig dauert, während Sie versuchen, sie abzubrechen. Aus diesem Grund kann die Laufzeit nicht garantieren, dass der Thread immer beendet wird, nachdem Sie ihn dazu aufgefordert haben.

ThreadAbortException hat mehr:

Wenn die Abort-Methode aufgerufen wird, um einen Thread zu zerstören, löst die Common Language Runtime eine ThreadAbortException aus. ThreadAbortException ist eine spezielle Ausnahme, die abgefangen werden kann, aber am Ende des catch-Blocks automatisch erneut ausgelöst wird. Wenn diese Ausnahme ausgelöst wird, führt die Laufzeit alle finally-Blöcke aus, bevor der Thread beendet wird. Da der Thread eine unbegrenzte Berechnung in den finally-Blöcken durchführen oder aufrufen kann Thread.ResetAbort(), um den Abbruch abzubrechen, gibt es keine Garantie dafür, dass der Thread jemals endet.

Das musst du nicht Abort() Thread manuell erstellen. Die CLR erledigt die gesamte Drecksarbeit für Sie, wenn Sie die Methode im Thread einfach zurückgeben. Dadurch wird der Thread normal beendet.

John Feminella
quelle
Ich muss es abbrechen (), da in diesem Thread eine Nachrichtenschleife gestartet wurde (Dispatcher.Run ();). Wenn ich es richtig verstehe, muss ich eine Methode aufrufen, die return in den Thread aufruft, um es zu beenden?
user101375
7

FileStream.Read()auf eine Named Pipe, die derzeit nichts empfängt (Anrufblöcke lesen, während auf eingehende Daten gewartet wird), wird nicht reagiert Thread.Abort(). Es bleibt im Read()Anruf.

jovain
quelle
6

Was ist, wenn ein Thread eine Sperre hält und abgebrochen / getötet wird? Ressourcen bleiben stecken

Es funktioniert gut, wenn ein Thread-Aufruf sich selbst abbricht, aber nicht von einem anderen Thread. Abbrechen, beendet den betroffenen Thread mit Gewalt, auch wenn er seine Aufgabe nicht abgeschlossen hat und keine Möglichkeit zum Bereinigen von Ressourcen bietet

Referenz MSDN


Siehe: Best Practices für verwaltetes Threading

Asad
quelle
5

Ich kann einen Thread, der in einer Schleife steckt, nicht abbrechen:

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

Ich kann den Thread jedoch abbrechen, wenn er während der Schleife schläft:

//mortal
Thread th2 = new Thread(() => { while (true) { Thread.Sleep(1000); }});
Colin
quelle
1
Dies scheint nicht wahr zu sein. Ich habe ein Testprogramm ausgeführt: `{var th = new Thread (() => {int i = 0; try {while (true) {i ++;}} catch (Ausnahme e) { Console.WriteLine ("@ {0} abbrechen", i);}}); th.Start (); Thread.Sleep (1000); th.Abort (); th.Join (); }
Weipeng L
3

Weil Sie das fangen ThreadAbortExceptionund Thread.ResetAbortim Handler anrufen können .

erikkallen
quelle
0

OT: Für eine umfassende, sprachunabhängige, fragwürdig nützliche und verdammt lustige Darstellung der Parallelität siehe Verity Stob !

Pontus Gagge
quelle
-1

Ich hatte Fälle, in denen der Thread zu beschäftigt war, um den Abort () -Aufruf zu hören, was normalerweise dazu führt, dass eine ThreadAbortingException in meinen Code ausgelöst wird.

Andy Shellam
quelle