2010-06-21 9 views
8

¿Existe una forma estándar de cerrar una aplicación "limpiamente" mientras que algunos objetos WaitHandle pueden estar en el estado de una llamada de bloqueo actual al WaitOne?¿Cómo cierras una aplicación cuando WaitHandle se encuentra en medio de una llamada a WaitOne?

Por ejemplo, puede haber un subproceso de fondo que está girando a lo largo de 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 es desanimado). Si llama al Close en el objeto _request (un AutoResetEvent), se lanzará una excepción.

En la actualidad, el hilo que ejecuta este bucle tiene la propiedad IsBackground establecido en true, y por lo tanto la aplicación aparece para cerrar correctamente. Sin embargo, dado que WaitHandle implementa IDisposable, no estoy seguro si esto se considera kosher o si ese objeto realmente debe eliminarse antes de que la aplicación finalice.

¿Es este un mal diseño? De lo contrario, ¿cómo se trata este escenario?

Respuesta

8

definir un adicional WaitHandle llamados _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(); 
    } 
} 
+0

Totalmente tiene sentido. Pero, ¿significa esto que * no * está bien tener simplemente el hilo ejecutando este bucle inicializado con 'IsBackground = true '(de modo que cuando la aplicación sale, el bucle termina aunque el' WaitHandle' aún está esperando)? –

+0

@Dan: Probablemente también esté bien, pero este método le permitirá finalizar el subproceso con elegancia sin tener que cerrar toda la aplicación. –

+0

Hola. Acabo de hacerte otra pregunta sobre este patrón. ¿Es este el patrón para detener un hilo mediante el identificador de espera? (en lugar de usar abort/interrupt)? –

1

Establezca la propiedad IsBackground en true ... debe cerrar automáticamente el hilo cuando finaliza su aplicación.

Alternativamente, puede interrumpir el hilo llamando al 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(); 
+0

¿Así que está diciendo que no hay necesidad de llamar 'Cerrar' en' WaitHandle' siempre que el hilo sea un hilo de fondo? –

+0

@Dan, siempre ha salido correctamente para mí ... Estoy buscando algo en la documentación para respaldar ese reclamo. – Kiril

+0

Esto es exactamente lo mismo que Thread.Abort(). Es solo que el CLR lo llamará. –

1

Cuando un hilo es el bloqueo (independientemente de lo que está bloqueando el) que pueda llame al Thread.Interrupt() Esto causará la excepción ThreadInterruptedException (creo que podría ser un poco diferente) Puede manejar esta excepción en el hilo mismo y hacer las necesarias limpiezas.

Vale la pena señalar que el hilo solo lanzará el ThreadInterruptedException cuando está bloqueando, si no está bloqueando, no se lanzará hasta que el siguiente intente bloquearlo.

Esta es la forma "segura" de terminar los hilos de lo que he leído sobre el tema.

también vale la pena señalar: si el objeto implementa IDisposable y un finializador (que lo hará si utiliza recursos no administrados) el GC llamará al finalizador que normalmente llama a disponer. Normalmente esto no es determinista. Sin embargo, puede garantizar que recibirán una llamada en la salida de la aplicación. Solo en circunstancias muy especiales no lo harían. (Se genera una excepción de terminación de entorno .net como StackOverflowException)

0

Creo que el sistema operativo se limpiará una vez que el proceso haya finalizado. Debido a que su hilo está marcado como IsBackground, el CLR terminará el proceso y todos los hilos dentro, por lo que esto no es un problema.

Cuestiones relacionadas