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?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top