Esperar a que los hilos acaben cuando termina un proceso
Una pregunta habitual relacionada con el desarrollo multihilo en plataforma .net es ¿Cómo espero a que los hilos que lanza mi aplicación acaben? El último que me la realizaba era uno de los alumnos del curso de Programación Multihilo que imparto en Campus MVP. No hay una respuesta única. La respuesta varia según se trate de un hilo que hemos creado explicitamente o un hilo que hayamos creado usando el pool de hilos de .Net.
El escenario que generalmente se plantea es que una aplicación lanza hilos, y queremos evitar que los hilos mueran sin concluir su trabajo cuando la aplicación termina.
Tenemos múltiples posibilidades:
Podemos antes de terminar el hilo principal de la aplicación, tener un tiempo durante el cual el hilo principal da tiempo a que el resto de hilos terminen. Para ello el hilo principal se duerme, y no crea más hilos. Para ello basta con poner una llamada a Sleep en las rutinas de finalización de nuestra aplicación.
//En aplicaciones Windows usamos el evento
//ThreadExit del objeto Application
static void Application_ThreadExit(object sender, EventArgs e)
{ //Damos tiempo a que acaben los hilos ya lanzados...
System.Threading.Thread.Sleep(10000);
}
//En servicios de Windows usamos la función OnStop
protected override void OnStop()
{ //Damos tiempo a que acaben los hilos ya lanzados...
System.Threading.Thread.Sleep(10000);
}
Pero esto puede no ser suficiente si necesitamos tener la certeza de que nuestros hilos acaben. Para ello podemos establecer IsBackground de los hilos que creamos a false.
Thread t = new Thread(new ThreadStart(ThreadMethod));
t.IsBackground = false;
t.Start();
De esta manera evitamos que el proceso muera mientras quedan hilos en ejecución. Eso si debemos tener en cuenta que esta aproximación puede interferir con el cierre de nuestras aplicaciones o incluso del sistema. Esto es especialmente molesto cuando los hilos los estamos creando en un servicio. Los servicios tienen un tiempo máximo para detenerse, trascurrido el cual el SCM lanza un error.
Cuando usamos el pool de hilos el proceso es un poco diferente, pues no tenemos acceso al hilo directamente. En cualquier caso desde la función de trabajo que pasamos a QueueUserWorkItem podemos obtener el hilo actual y establecer su propiedad IsBackground a false.
ThreadPool.QueueUserWorkItem(new WaitCallback(WorkMethod));
...
static void WorkMethod()
{ //Antes de realizar ningún proceso establecemos la propiedad
//IsBackgrount a true
Thread.CurrentThread.IsBackground = false;
}