Ejecutar nuevos hilos con parámetros y recibir respuesta de ellos

 

Fecha: 09/Sep/2005 (03/Sep/2005)
Autor: Gerardo Contijoch (mazarin9@yahoo.com.ar)

 


Antes de empezar debo aclarar que la información para escribir este artículo la saque de MSDN Library para el Framework .NET 2.0. Como estas técnicas son válidas tambien para los Frameworks 1.0 y 1.1, decidi transcribirlas aca para que esten al alcance de todos.

Iniciar nuevos hilos con parámetros

Debido a que no es posible ejecutar un nuevo hilo sobre un delegado a un método que requiere parámetros, vamos a tener que rebuscarnosla para hacerle llegar al método los parametros necesarios para su ejecución.
La técnica consiste en crear una clase que va a contener los parametros del método (en forma de propiedades o campos) y que implemente el método en cuestión. De esta forma los parámetros estarán al alcance siempre que el método los necesite. El siguiente código muestra un ejemplo:

class ClasePrincipal{

    static void Main(string[] args) {
        Console.WriteLine("Iniciando void Main().");

        // Creamos una instancia de la clase multi hilo y seteamos los campos que normalmente pasariamos como parametros
        ClaseMultiHilo cmh = new ClaseMultiHilo();
        cmh.PrimerNumero = 14;
        cmh.SegundoNumero = 1;

        // Creamos un delegado para el método ImprimirSuma()
        ThreadStart ts = new ThreadStart(cmh.ImprimirSuma);

        // Creamos un hilo para ejecutar el delegado...
        Thread t = new Thread(ts);

        // Iniciamos la ejecucion del nuevo hilo
        t.Start();
        // Esperamos a que termine la ejecucion del hilo
        t.Join();

        Console.WriteLine("Fin de la ejecución. Presione una tecla para salir.");
        Console.ReadLine();
        }
    }

    class ClaseMultiHilo
    {
        public int PrimerNumero = 0;
        public int SegundoNumero = 0;

        public void ImprimirSuma(){
            Console.WriteLine("Calculando suma...");
            Thread.Sleep(2000);
            Console.WriteLine(string.Format("La suma de {0} y {1} es {2}", this.PrimerNumero, this.SegundoNumero, this.SegundoNumero + this.PrimerNumero));
        }
    }
}

No hay mucho por explicar. Antes de ejecutar el método, nos aseguramos de haber seteado los parametros que este usará y listo. No hay ningún misterio en el resto.

Ahora veamos como obtener valores del método a ejecutar en un nuevo hilo.

Recibir valores luego de la ejecución de un hilo

Este método no difiere mucho del anterior. La diferencia radica en que vamos a tener que complicarnos un poco con eventos. Los eventos nos serviran para saber cuando se termino la ejecución del hilo, y de paso, para pasarnos los resultados de la ejecución. Para hacerlo vamos a crear una clase que contenga el método a ejecutar (al igual que en el ejemplo anterior) y un evento, el cual será lanzado cuando el método termine su ejecución. Este evento estará asociado a un delegado el cual aceptará los parametros a devolver. Cuando creemos un handler para el evento (instanciando al delegado), al ejecutarse el evento, el handler se va a encargar de hacernos llegar los datos que necesitamos. Es complicado en palabras, veamos otro ejemplo:

// Este es el delegado que se encargará de hacer la magia
public delegate void SumaCalculadaDelegate(int suma);

class ClasePrincipal{

    static void Main(string[] args) {
        Console.WriteLine("Iniciando void Main().");

        // Creamos una instancia de la clase multi hilo y seteamos los campos que normalmente pasariamos como parametros
        ClaseMultiHilo cmh = new ClaseMultiHilo();
        cmh.PrimerNumero = 14;
        cmh.SegundoNumero = 1;

        // Agregamos el handler del evento (si no lo hacemos no podremos interceptarlo)
        cmh.SumaCalculada += new SumaCalculadaDelegate(SumaTermino);
        
        // Creamos un delegado para el método ImprimirSuma()
        ThreadStart ts = new ThreadStart(cmh.CalcularSuma);

        // Creamos un hilo para ejecutar el delegado...
        Thread t = new Thread(ts);  

        Console.WriteLine("Fin de la ejecución. Presione una tecla para salir.");
        Console.ReadLine();
    }

    public static void SumaTermino(int suma){
        Console.WriteLine ("Se recibio el siguiente valor al calcular la suma: " + suma.ToString());
    }
}

class ClaseMultiHilo
{
    public event SumaCalculadaDelegate SumaCalculada;

    public int PrimerNumero = 0;
    public int SegundoNumero = 0;

    public void CalcularSuma(){
        // Lanzamos el evento con la informacion necesaria
        SumaCalculada(this.PrimerNumero + this.SegundoNumero);
    }
}

Como se ve, en este ejemplo nos valemos de la primer técnica para pasarle parametros al método a ejecutarse en otro hilo.

Cabe destacar que podremos devolver más de un único valor ya que no hay límites en la cantidad de argumentos que acepta el delegado.

Hay algo que no me gusta mucho del ejemplo anterior y es que no sabemos cuando puede terminar la ejecucion del hilo. Si nosotros deseamos recibir información de éste, no hay duda de que llegaremos a un punto en el que necesitaremos esta información. Ahora, ¿comó sabemos hasta donde llegar? Bueno, hay otra manera (ademas de la vista recien) de saber cuando se termina la ejecución del hilo y es ejecutando la siguiente línea:

t.Join();

Esto hace que se sincronice el hilo en el que estamos trabajando y el hilo creado. Así, con agregar esta línea en el momento en que necesitamos utilizar la información procesada en el otro hilo habremos resuelto el problema ya que no se continuará con la ejecución hasta que haya finalizado el hilo "hijo" (lo que nos asegurará de que se lanzó el evento que creamos).

Espero que les sea de utilidad! En el código que acompaña a este artículo, podrán ver una fusión de los ejemplos antes vistos.


Espacios de nombres usados en el código de este artículo:

System.Threading

 


Fichero con el código de ejemplo: qrox_parametrosthreading.zip - 7 KB


ir al índice