¿Cómo cerrar una aplicación cuando algunos WaitHandle se encuentra en medio de una llamada a WaitOne?

StackOverflow https://stackoverflow.com/questions/3087683

Pregunta

¿Hay una manera estándar para cerrar una aplicación "limpiamente", mientras que algunos objetos WaitHandle pueden estar en el estado de una llamada de bloqueo actual para WaitOne?

Por ejemplo, puede haber un subproceso de fondo que está girando a lo largo en un método como este:

while (_request.WaitOne())
{
    try
    {
        _workItem.Invoke();
    }
    finally
    {
        OnWorkCompleted();
    }
}

No veo ninguna manera obvia de disponer de este hilo sin llamar Thread.Abort (que por lo que entiendo se desalienta). Llamando Close en el objeto _request (un AutoResetEvent), sin embargo, va a lanzar una excepción.

En la actualidad, el hilo que ejecuta este bucle tiene su conjunto de propiedades IsBackground a true, y por lo tanto la aplicación aparece para cerrar correctamente. Sin embargo, desde implementos WaitHandle IDisposable, estoy seguro si esto se considera kosher o si ese objeto en realidad debería ser eliminado antes de que las salidas de aplicaciones.

Es un mal diseño? Si no, ¿cómo está este escenario típicamente tratado?

¿Fue útil?

Solución

Definir un WaitHandle adicional llamado _terminate que señalará una petición para terminar el bucle y luego usar WaitHandle.WaitAny en lugar de WaitHandle.WaitOne.

var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
  try
  {
    _workItem.Invoke();
  }
  finally
  {
    OnCompleteWork();
  }
}

Otros consejos

Cuando un hilo es el bloqueo (independientemente de lo que está bloqueando el) se puede llamar Thread.Interrupt() Esto hará que el ThreadInterruptedException excepción (creo, que podría ser un poco diferente) Puede manejar esta excepción en el mismo hilo y realice una NECESARIO limpiar.

Vale la pena señalar, que el hilo sólo tirar la ThreadInterruptedException cuando se está bloqueando, si no es el bloqueo no será lanzado hasta la próxima intenta bloquear.

Esta es la forma "segura" de poner fin a las discusiones de lo que he leído sobre el tema.

También vale la pena destacar: Si implementa el objeto tanto IDisposable y una finializer (que lo hará si se utiliza recursos no administrados) del GC llamarán al finalizador que normalmente exige disponer. Normalmente esto no es determinista. Sin embargo se puede casi garantizar que se llamará en la salida de la aplicación. Sólo en circunstancias muy especiales que no lo harían. (A .NET entorno termininating excepción tales como StackOverflowException es lanzada)

Configurar la propiedad IsBackground a true ... lo que debería cerrarse automáticamente el hilo cuando termine su aplicación.

Como alternativa, se puede interrumpir el hilo llamando Thread.Interrupt y manejar el ThreadInterruptedException . Otra idea es llamar _request.Set() y hacer que el bucle while comprobar un indicador volátil para determinar si la aplicación se está cerrando o si debe continuar:

private volatile bool _running = true;
while(_request.WaitOne() && _running)
{
    //...
}

// somewhere else in the app
_running = false;
_request.Set();

Creo que el sistema operativo va a limpiar los desechos de su proceso ha terminado. Debido a que el hilo se marca como IsBackground el CLR se termina el proceso y todos los hilos en el interior, por lo que este no es un problema.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top