Gibt es eine Möglichkeit, einen schlafenden Thread zu unterbrechen? Wenn ich einen ähnlichen Code habe.
%Vor%Ich möchte DoWork () jede Stunde ausführen. Also würde ich gerne ein bisschen länger als 10 Sekunden schlafen. Sagen Sie alle 10 Minuten einen Scheck. Wenn ich jedoch den Ruhezustand auf 10 Minuten einstelle und diese Hintergrundaufgabe beenden möchte, muss ich warten, bis der Schlaf wieder aufgenommen wird.
Mein tatsächlicher Code verwendet ein Threading.ManualResetEvent, um die Hintergrundarbeit herunterzufahren, aber mein Problem ist mit dem ThreadSleep-Code. Ich kann bei Bedarf mehr Code posten.
OK, ich werde hier ein bisschen vollständiger Code hinzufügen, da ich denke, dass es einige der Fragen beantworten wird.
%Vor%Mein Problem ist hier,
%Vor%Dies wartet auf den Thread.Sleep in ExecuteWorker (), der in meinem Hintergrundthread ausgeführt wird.
Anstatt Thread.Sleep
zu verwenden, verwenden Sie ManualResetEvent.WaitOne
.
Wo terminate
ein ManualResetEvent
1 ist, können Sie Set
anfordern, um die Schleife zu beenden.
Aktualisierung:
Ich habe gerade bemerkt, dass Sie sagten, Sie benutzen bereits ManualResetEvent
, um die Hintergrundarbeit zu beenden (ich nehme an, dass das in DoWork
ist). Gibt es einen Grund, warum Sie nicht dasselbe MRE verwenden können? Wenn das nicht möglich ist, sollte es kein Problem geben, ein anderes zu verwenden.
Update 2:
Ja, statt Thread.Sleep(5000)
in ExecuteWorker
stattdessen _shutdownEvent.WaitOne(5000)
. Es würde wie folgt aussehen.
1 Es gibt auch eine ManualResetEventSlim
-Klasse in .NET 4.0.
Anstatt Thread.Sleep
zu verwenden, kannst du Monitor.Wait
mit einem Timeout verwenden - und dann kannst du Monitor.Pulse
von einem anderen Thread verwenden, um es aufzuwecken.
Vergessen Sie nicht, dass Sie den Monitor vor dem Aufruf von Wait
oder Pulse
:
Sie können Thead.Interrupt verwenden, um einen schlafenden Thread aufzuwecken . Es wird ein ThreadInteruptedException
auf dem blockierten Thread verursachen, also ist es nicht der eleganteste oder effizienteste Ansatz.
Sie müssen auch müde sein, dass das Unterbrechen eines Threads auf diese Weise unsicher ist. Es bietet keine Kontrolle über den Punkt, an dem der Thread abgebrochen wird, und sollte daher nicht ohne sorgfältige Abwägung der Konsequenzen verwendet werden. Wie bereits in anderen Antworten erwähnt, ist es weitaus besser, signalbasierte Techniken zu verwenden, um zu steuern, wann der Thread kontrolliert endet.
Können Sie nicht einfach Ihren Thread.Sleep-Teil in eine Schleife wickeln, so dass er 60-mal durchläuft und dann die andere prüft? Natürlich handelt es sich hierbei um Trades von einem einfachen if (somethingIndicatingQuit) gegenüber dem DateTime, wenn man nachschaut, aber vorausgesetzt, dass echter Code etwas teurer macht, könnte eine zweite Schleife kleinere CPU-Einsparungen bringen .
Wenn Sie jede Stunde mit DoWork () arbeiten möchten, warum berechnen Sie nicht die Anzahl der ms, die bis zur nächsten Stunde benötigt wird, und warten Sie auf diese Zeit? Um den Schlaf aufzuheben, könntest du entweder eine waitable Synchro-Klasse verwenden, wie den von @ Jon Skeet vorgeschlagenen Monitor, oder einfach eine Markierung im Thread setzen, die besagt, dass er nach dem Schlaf statt DoWork () beendet und einfach vergessen wird - entweder der Thread wird sich selbst töten, wenn die Zeit abgelaufen ist, oder Ihr Betriebssystem wird ihn beim Schließen der App beenden, je nachdem, was zuerst eintritt.
Rgds, Martin
Warum nicht eine BlockingCollection verwenden? Ich sehe es als einen viel eleganteren Ansatz als die angenommene Antwort. Ich denke auch nicht, dass es viel Overhead im Vergleich zum Monitor gibt.
Hier ist, wie es geht:
initialisiert eine BlockingCollection als Mitglied:
%Vor%statt
%Vor%tu dies
%Vor%um es aufzuwecken, können Sie diesen Code verwenden
%Vor%Tags und Links c# multithreading