Wie wollen Sie schließen eine Anwendung, wenn einige Waithandle in der Mitte eines Anrufs zu WaitOne ist?
-
28-09-2019 - |
Frage
Gibt es eine standardisierte Möglichkeit, eine Anwendung „sauber“ zu schließen, während einige WaitHandle
Objekte in dem Zustand eines Stromsperr Aufruf WaitOne
sein können?
Zum Beispiel kann ein Hintergrund-Thread sein, die zusammen in einem Verfahren wie diese dreht:
while (_request.WaitOne())
{
try
{
_workItem.Invoke();
}
finally
{
OnWorkCompleted();
}
}
Ich sehe keine offensichtliche Art und Weise von diesem Thread zu verfügen, ohne Thread.Abort
Aufruf (was von dem, was ich verstehe, wird abgeraten). Der Aufruf Close
auf dem _request
Objekt (ein AutoResetEvent
), jedoch wird eine Ausnahme werfen.
Zur Zeit der Faden, der diese Schleife läuft, hat seine IsBackground
Eigenschaft auf true
und so die Anwendung erscheint richtig zu schließen. Da jedoch WaitHandle
Arbeitsgeräte IDisposable
, ich bin nicht sicher, ob dies als koscher oder wenn das Objekt wirklich sollte, bevor die App Ausfahrten entsorgt werden.
Ist das ein schlechtes Design? Wenn nicht, wie wird dieses Szenario normalerweise behandelt?
Lösung
Definieren Sie eine zusätzliche WaitHandle
genannt _terminate
, die eine Anforderung signalisiert, die Schleife zu beenden, und dann verwendet WaitHandle.WaitAny
statt WaitHandle.WaitOne
.
var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
try
{
_workItem.Invoke();
}
finally
{
OnCompleteWork();
}
}
Andere Tipps
Wenn ein Thread blockiert (unabhängig davon, was sie blockt auf) können Sie Thread.Interrupt()
nennen dies die Ausnahme ThreadInterruptedException
verursachen wird (ich glaube, es könnte ein wenig anders sein) Sie diese Ausnahme auf den Faden umgehen kann selbst und machen jede neccesary aufzuräumen.
Es ist erwähnenswert,, dass der Faden nur die ThreadInterruptedException
werfen, wenn es blockiert, wenn es nicht blockiert wird es nicht bis zum nächsten versucht, Block geworfen werden.
Dies ist der „sichere“ Weg Threads zu beenden, was ich zu diesem Thema gelesen habe.
auch bemerkenswert: Wenn das Objekt implementiert sowohl IDisposable und ein finializer (was es wird, wenn es nicht verwalteten Ressourcen verwendet) der GC wird die Finalizerthread nennen, die normalerweise dispose nennt. Normalerweise ist dies nicht deterministisch. Allerdings können Sie ziemlich viel garantieren sie auf das Beenden der Anwendung aufgerufen. Nur unter ganz besonderen Umständen würden sie nicht. (A .net Umgebung termininating Ausnahme wie StackOverflowException
geworfen wird)
Stellen Sie die IsBackground
Eigenschaft true
... es sollte automatisch schließen, der Faden, wenn Ihre Anwendung endet.
Alternativ können Sie den Thread unterbrechen durch den Aufruf Thread.Interrupt
und behandeln die ThreadInterruptedException
. Eine weitere Idee ist _request.Set()
anrufen und die while-Schleife ein flüchtiges Flag, um zu bestimmen machen zu überprüfen, ob die Anwendung endet oder wenn sie fortgesetzt werden sollten:
private volatile bool _running = true;
while(_request.WaitOne() && _running)
{
//...
}
// somewhere else in the app
_running = false;
_request.Set();
ich denke, das Betriebssystem aufzuräumen nach dem Prozess abgeschlossen ist. Da Ihr Thread als IsBackground markiert die CLR wird den Prozess und alle Fäden innerhalb enden, so dass dies kein Problem ist.