La clase ThreadPool
Lear TI Capacitación

Guía de preparación del examen 70-483: Programming in C#

Habilidad: Administración del flujo de un programa
Tema: Implementación del procesamiento asincrónico y de subprocesos
Por Miguel Muñoz Serafín

La clase ThreadPool

La clase estática System.Threading.ThreadPool proporciona un grupo de hilos (Pool of Threads) que puede ser utilizado para ejecutar tareas, colocar elementos de trabajo, procesar operaciones asíncronas, esperar por otros hilos y procesar temporizadores.

Ejercicio
Explorando la clase ThreadPool

Realiza los siguientes pasos para conocer la funcionalidad básica de la clase ThreadPool.

  1. Crea una aplicación de consola utilizando la plantilla Console App (.NET Framework).

    El ThreadPool nos permite utilizar hilos de una manera eficiente proporcionando a una aplicación un área (pool) donde podemos agregar elementos de trabajo (work ítem) que son administrados por el sistema.

    La clase ThreadPool ofrece el método QueueUserWorkItem que nos permite colocar un elemento de trabajo en el pool de threads para que sea ejecutado en el siguiente hilo disponible.

  2. Agrega el siguiente código para crear un hilo donde el método a ejecutar no requiere parámetros.

    Thread T = new Thread(() => Console.WriteLine("Hola ThreadStart"));

    El delegado ThreadStart tiene la siguiente firma:

    public delegate void ThreadStart();

    Cualquier método o expresión lambda que no devuelva valor y que no defina parámetros puede ser especificado como delegado del constructor de la clase Thread.

  3. Agrega el siguiente código para crear un hilo donde el método a ejecutar requiere un parámetro.

    Thread T1 = new Thread(
    (obj) => Console.WriteLine($"Hola ParameterizedThreadStart: {obj}"));

    El delegado ParameterizedThreadStart tiene la siguiente firma:

    public delegate void ParameterizedThreadStart(object obj);

    Cualquier método o expresión lambda que no devuelva valor y que defina un parámetro de tipo object puede ser especificado como delegado del constructor de la clase Thread. El método ejecutado por el delegado puede realizar una conversión del valor del parámetro hacia el tipo apropiado.

    Para iniciar la ejecución de un hilo, invocamos al método Start de la instancia Thread.

  4. Agrega el siguiente código para iniciar la ejecución de los hilos creados anteriormente.

    T.Start();
    T1.Start(100);

    Puedes notar que el valor del parámetro del delegado es pasado en la llamada al método Start.

  5. Ejecuta la aplicación y observa el resultado.

    Las instancias de la clase Thread pueden representar hilos de primer plano (foreground thread) o hilos de segundo plano (background thread). Ambos tipos de hilos son idénticos excepto que un hilo de segundo plano no hace que un proceso se mantenga en ejecución si todos los hilos de primer plano han terminado. Una vez que todos los hilos de primer plano han terminado, el motor de tiempo de ejecución detiene todos los hilos de segundo plano y finaliza el proceso.

    De manera predeterminada, al crear y ejecutar un hilo con la clase Thread, el hilo se ejecuta como un hilo de primer plano.

  6. Agrega el siguiente código al final del método Main para ejecutar un proceso en un hilo de primer plano. Puedes notar que utilizamos el método estático Sleep para suspender la ejecución del hilo actual por 2000 milisegundos.

    Thread T2 = new Thread(() =>
    {
    Thread.Sleep(2000);
    Console.WriteLine("El hilo T2 despertó");
    });
    T2.Start();
    Console.WriteLine("Fin del hilo principal");

  7. Ejecuta la aplicación. Puedes notar que la aplicación no finaliza hasta que el hilo T2 finaliza.

    En cualquier momento, podemos modificar un hilo para que se ejecute en segundo plano o primer plano estableciendo el valor de la propiedad IsBackground.

  8. Modifica el siguiente código para mostrar el momento en que empieza la ejecución del hilo y especificar que el hilo T2 se ejecute en segundo plano.

    Thread T2 = new Thread(() =>
    {
    Console.WriteLine("El hilo T2 dormirá");

    Thread.Sleep(2000);
    Console.WriteLine("El hilo T2 despertó");
    });

    T2.IsBackground = true;

    T2.Start();
    Console.WriteLine("Fin del hilo principal");

  9. Ejecuta la aplicación. Puedes notar que la aplicación finaliza sin esperar a que el hilo de segundo plano finalice su ejecución (no se muestra el mensaje “El hilo T2 despertó”).

    La clase Thread expone propiedades que proporcionan información sobre el hilo. En algunos casos también podemos establecer el valor a esas propiedades para controlar la operación del hilo.

  10. Agrega el siguiente código para ejemplificar el uso de las propiedades más comunes de la clase Thread.

    // Obtener el hilo que está ejecutando el código actual
    Thread CT = Thread.CurrentThread;
    // Mostrar el identificador único de un hilo dentro del proceso
    Console.WriteLine($"Id del hilo actual: {CT.ManagedThreadId}");
    // Mostrar el estado de un hilo
    Console.WriteLine($"Estado del hilo actual: {CT.ThreadState}");
    // Mostrar la prioridad de un hilo
    Console.WriteLine($"Prioridad del hilo actual: {CT.Priority}");
    // Mostrar si un hilo es hilo del Thread Pool
    Console.WriteLine(
    $"¿El hilo actual es del Thread Pool? {CT.IsThreadPoolThread}");
    // Mostrar si es un hilo de segundo plano
    Console.WriteLine(
    $"¿El hilo actual es de segundo plano? {CT.IsBackground}");

  11. Ejecuta la aplicación. Podrás ver los valores de las propiedades.

En este ejercicio, exploramos la funcionalidad básica de la clase Thread.

Para más información, se recomienda consultar el siguiente enlace:

Thread Class