Hola!
Hoy voy a hacer un artículo sobre sincronización de hilos. He visto alguna que otra vez una forma poco correcta de hacer que un hilo padre espere a que su hijo haya terminado (como quedarse en un bucle con un Sleep y comprobar periódicamente si el hilo hijo está vivo), así que voy a explicar una forma muy sencilla de coordinar los hilos.
Como ejemplo podemos usar un servicio de Windows, ya que en estos servicios, la creación de un hilo suele ser casi imprescindible, porque lo normal es que cuando el servicio arranca nosotros generalmente querremos que el servicio se quede activo, pero debemos salir del método OnStart del servicio tan pronto como sea posible para evitar un Timeout en el arranque.
Además, sería interesante que cuando paramos el servicio, en el método OnStop del servicio, el hilo principal espere a que el hilo hijo termine aquello que esté haciendo en ese momento, para no cortar alguna operación que se pueda estar realizando cuando se quiere parar el servicio.
Para conseguir esto, en nuestra clase del servicio podemos declarar un miembro que contenga un WaitHandle en el que almacenaremos si nuestro hilo hijo ha terminado su ejecución. Este WaitHandle es el que usará el hilo padre para esperar al hilo hijo.
Una breve descripción de lo que haremos en el servicio será lo siguiente:
- Al arrancar el servicio, crearemos un hilo nuevo en el ThreadPool, usando el método QueueUserWorkItem, al que le pasaremos el WaitHandle que hemos definido en la clase. Como WaitHandle es una clase abstracta, podemos usar (por ejemplo) un AutoResetEvent.
- Al parar el servicio, esperaremos a que el hilo hijo que creamos al arrancar el servicio termine su ejecución. Para ello usaremos el método estático WaitAll de la clase WaitHandle, pasándole como argumento el objeto estático de tipo WaitHandle que usamos al arrancar el servicio.
- En el método que ejecuta el hilo hijo debemos:
- Recibir el objeto WaitHandle (AutoResetEvent) que nos pasa el hilo que nos ha creado, y almacenarlo.
- Agrupar la ejecución del servidor en un bloque try { … } finally { … } (se puede-debe poner un catch), y en el finally deberemos notificar que hemos terminado la ejecución, llamando al método Set del objeto AutoResetEvent que hemos recibido, así nos aseguramos de que notificaremos que hemos terminado la ejecución del hilo hijo al hilo padre.
Bueno, pues ésta es la idea básicamente.
Saludos!