Wie zu stoppen worker-threads in einer Multithread-Windows-Dienst auf Dienst stoppen
Ich habe einen Windows-Dienst, nutzt die producer/consumer-Warteschlange Modell mit mehreren worker-threads, die Verarbeitung von tasks aus einer Warteschlange. Diese Aufgaben können sehr lange laufen, in der Reihenfolge von vielen Minuten wenn nicht Stunden, und nicht mit Schleifen.
Meine Frage ist, über die beste Art das zu handhaben, den service zu stoppen zu anmutig-end-Verarbeitung auf diese worker-threads. Ich habe gelesen, in einem anderen ALSO Frage, dass die Verwendung von thread.Abort() wird ein Zeichen für schlechtes design, aber es scheint, dass der service OnStop () - Methode wird nur eine begrenzte Menge an Zeit, um zu beenden, bevor der Dienst beendet wird. Ich tun kann, ausreichend clean-up in die Fänge zum "ThreadAbortException" - (es gibt keine Gefahr von inkonsistenten Zustand), so aufrufenden thread.Abort() auf den worker-threads scheint OK zu mir. Ist es? Was sind die alternativen?
- eine endgültige Lösung mit source code-Beispiel?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Tatsächlich
Abort
sollte vermieden werden. Am besten wäre es, Ihnen etwas Zeit, um würdevoll beenden - dann vielleicht nach einem timeout, vielleicht erwägen den Abbruch der Ihnen - aber letztlich, service stoppen kann, tun genau das gleiche durch Tötung der Prozess statt.Ich würde versuchen, ein signal in meinem Warteschlangen, der sagt "flush and exit" - ähnlich wie die
Close
Methode hier, sondern mit einer Art von signal, wenn abzuschließen.Wenn Sie greifen, um
Abort
- betrachten Sie den Prozess mit tödlichem Ausgang. Töten Sie so schnell wie möglich.Erstellen Sie einen task-Typ für "shutdown" und zu injizieren, der in Ihre producer - /consumer-Warteschlange einmal für jeden worker-thread.
Dann verwenden Sie Thread.Join (mit timeout), um sicherzustellen Herunterfahren abgeschlossen ist.
Mit .NET 4.0 nutzen Sie die
System.Threading.Tasks
namespace zu nutzen, dieTask
Objekt. In einer nussschale, können Sie einenCancellationToken
zu mehr ordnungsgemäß zu behandeln Stornierung/Abbruch in den Aufgaben, sei es lang oder kurz ausgeführt.Sehen hier weitere details aus der MSDN-Website.
Sich die Frage, wie geändert, hat eigentlich weniger zu tun mit dem Durchzug und mehr zu tun, wie zu stoppen, lange Ausführung von Aktionen. Ich persönlich benutze immer die APM, die für lange Strom-und Kommunikations-Aktivitäten wie etwa große Datei-transfers. Jeder callback läuft auf einem E /a-Abschluss-pool-thread und schnell abgeschlossen, die Verarbeitung einen bescheidenen Batzen und planen die nächste übergeben. Anstehenden Operationen können abgebrochen werden, indem Sie einfach aufrufen
Close()
auf das socket-Objekt. Das ist viel billiger und effizienter als die DIY-thread-management.Wie bereits erwähnt, ist
Abort()
schlechtes karma und sollte vermieden werden.Material unten geschrieben wurde, vor dem Ausschluss von der looping-Fall aus der Frage.
Wenn lang laufende Prozesse-Schleife sollten Sie alle enthalten eine exit-flag in Ihre loop-Bedingung, so dass Sie das signal, Sie zu beenden.
Streng, die Sie nutzen sollten volatile da aber nur die Kontroll-Logik überhaupt wird das flag spielt es keine Rolle. Technisch existiert eine race condition aber das bedeutet nur, Sie könnte gehen, eine Runde mehr Zeit.
Verwenden ManualResetEvent, um zu überprüfen, wenn ein Ereignis signalisiert wird, siehe Beispiel auf Thread-Synchronisation C# Programming Guide)
Hier ist ein code, den ich verwenden für das stoppen von threads in einem Windows-Dienst (wohlgemerkt ich benutze Threads direkt und nicht mit thread-pools):
Wenn Ihr Prozess wird trotzdem Herunterfahren, ich persönlich sehe nicht das problem bei der Verwendung von Abort(). Ich würde versuchen, einen anderen Weg finden, aber am Ende ist es egal, wenn werden Sie tun clean-up in der main-thread sowieso.
Eine andere option wäre, markieren Sie Ihre worker-threads als hintergrund threads. Auf diese Weise, Sie werden automatisch geschlossen, wenn der Prozess geschlossen wird. Sie können möglicherweise verwenden Sie die Anwendungsdomäne.ProcessExit event zu bereinigen, bevor Sie verlassen.