Come si fa a chiudere l'applicazione una certa WaitHandle è nel bel mezzo di una chiamata a WaitOne?
-
28-09-2019 - |
Domanda
C'è un modo standard per chiudere un'applicazione "pulito", mentre alcuni oggetti WaitHandle
possono essere in stato di una chiamata di blocco corrente WaitOne
?
Per esempio, ci può essere un filo di fondo che gira lungo in un metodo come questo:
while (_request.WaitOne())
{
try
{
_workItem.Invoke();
}
finally
{
OnWorkCompleted();
}
}
non vedo alcun modo ovvio di disporre di questa discussione senza chiamare Thread.Abort
(che da quanto ho capito è sconsigliato). Chiamando Close
sull'oggetto _request
(un AutoResetEvent
), tuttavia, un'eccezione.
Al momento, il thread che esegue questo ciclo ha la proprietà insieme alla IsBackground
true
, e quindi l'applicazione appare per chiudere correttamente. Tuttavia, dal momento che implementa WaitHandle
IDisposable
, io sono sicuro se questo è considerato kosher o se quell'oggetto in realtà dovrebbe essere smaltito prima che le uscite app.
E 'un brutto disegno? Se no, come è questo scenario tipicamente affrontato?
Soluzione
Definire un WaitHandle
aggiuntivo chiamato _terminate
che segnalerà la richiesta di terminare il ciclo e quindi utilizzare WaitHandle.WaitAny
anziché WaitHandle.WaitOne
.
var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
try
{
_workItem.Invoke();
}
finally
{
OnCompleteWork();
}
}
Altri suggerimenti
Quando un thread sta bloccando (indipendentemente da ciò che sta bloccando via) è possibile chiamare Thread.Interrupt()
Questo farà sì che la ThreadInterruptedException
eccezione (credo, potrebbe essere un po 'diversa) È possibile gestire questa eccezione sul filo stesso e fare qualsiasi neccesary ripulire.
Vale la pena notare, che il filo getterà solo il ThreadInterruptedException
quando sta bloccando, se non è il blocco non sarà gettato fino a quando si cerca di bloccare prossimi.
Questo è il modo "sicuro" di finire le discussioni da quello che ho letto su questo argomento.
anche degno di nota: se gli strumenti oggetto sia IDisposable e un finializer (che lo farà se utilizza risorse non gestite) il GC chiameranno il finalizzatore che chiama normalmente Dispose. Normalmente questo è non-deterministico. Tuttavia si può tranquillamente garantire che verrà chiamato in uscita dell'applicazione. Solo in circostanze molto particolari che non avrebbe fatto. (A .net eccezione termininating ambiente come StackOverflowException
è gettato)
Impostare la proprietà IsBackground
per true
... dovrebbe chiude automaticamente il filo quando la vostra estremità app.
In alternativa, si può interrompere il filo chiamando Thread.Interrupt
e gestire il ThreadInterruptedException
. Un'altra idea è quella di chiamare _request.Set()
e fare controllare il ciclo while una bandiera volatili per determinare se l'applicazione sta chiudendo o se deve continuare:
private volatile bool _running = true;
while(_request.WaitOne() && _running)
{
//...
}
// somewhere else in the app
_running = false;
_request.Set();
Credo che il sistema operativo sarà pulire dopo il processo è terminato. Perché il vostro filo è contrassegnato come IsBackground il CLR si concluderà il processo e tutti i fili all'interno, quindi questo non è un problema.