miércoles, 9 de julio de 2014

Receta C# No. 4-6: Ejecución de un Método sobre un Nuevo Thread

Tabla de Contenido

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
3.1 Delegado ThreadStart
3.2 Delegado ParameterizedThreadStart
4. Práctica: Código C#
5. Conclusiones
6. Glosario
7. Literatura & Enlaces

0. Introducción

Continuamos con la serie de recetas en C# enfocadas a threads, procesos, y sincronización. En esta ocasión aprenderemos los principios y práctica acerca de la ejecución de un método sobre un thread. Veremos a través de esta receta la oportunidad de crear diferentes hilos o threads de ejecución para procesos (métodos) que se ejecuten en paralelo. Además, volveré a definir los diferentes delegados disponibles en la BCL (Base Class Library) compatibles con las firmas de los constructores sobrecargados de la clase Thread.

1. Problema

Al crear una aplicación y declarar el punto de entrada (i.e., Main) para la ejecución de esta, ya contamos con un thread en ejecución al que podríamos referirnos como el thread principal (de ahí su nombre). Sabemos que el hardware moderno cuenta con capacidades para la ejecución en paralelo de múltiples procesos; de ahí que requiramos conocer y explorar la técnica necesaria para ejecutar un método en paralelo con el thread Main.

2. Solución

En la receta multithreading Cómo Crear un Thread ya hemos aprendido a crear un thread a través del uso de la clase Thread y el delegado ThreadStart. Aquí volveremos a utilizar estos artefactos de programa, además del delegado ParameterizedThreadStart para pasar datos al método que se ejecutará en paralelo con el método Main.

Por otro lado, este es el esquema general para la ejecución de un método en un nuevo thread:
  1. Crear un método compatible con una de las firmas de los delegados ThreadStart o ParameterizedThreadStart.
  2. Crear una instancia de Thread (System.Threading).
  3. Al constructor de Thread pasar una instancia explícita o implícita de uno de los delegados mencionados en el paso 1, además de la referencia al método que se ejecutará en paralelo. (Este método puede ser de instancia o estático.)
  4. Invocar el método Start para iniciar la ejecución del método creado en el paso 1.

3. Discusión de la Solución

A través de la creación de un método sobre un nuevo thread empezamos a descubrir los primeros principios y práctica sobre el control de ejecución de procesos en paralelo [1]. En la receta R4-1 (Ejecución de un Método sobre un Pool de Threads) reconocimos que es posible crear un conjunto (pool) de threads para que se ejecuten automáticamente por threads que se crean y se destruyen automáticamente después y antes de ejecutar un método o conjunto de métodos, respectivamente. Lo anterior para demostrar el grado de empoderamiento que alcanzamos al poder decidir cuando debe iniciar la ejecución de un método sobre un thread. En las sub-secciones que se presentan a continuación discutiremos cómo alcanzar esta tarea usando la clase Thread, y los delegados ThreadStart y ParameterizedThreadStart.

3.1 Delegado ThreadStart

El delegado ThreadStart [4] se haya en el nombre de espacio System.Threading. Con este delegado podemos encapsular o referenciar un método de instancia o estático que cumpla con la firma impuesta por este:

public delegate void ThreadStart()

Descripción puntual:
  • Tipo de retorno: void
  • Parámetros: «ninguno»
La tarea básica de este delegado es la ejecución indirecta de un método sobre un nuevo thread.

Ejemplo de uso:



En la línea 25 creamos una instancia de la clase UsoDelegadoThreadStart (definida en las líneas 6-38). Al constructor de esta clase le pasamos un valor entero (7) para inicializar el campo de instancia valor (línea 8). Las dos partes contundentes de este ejemplo de ThreadStart ocurren en las líneas:

  • Línea 30: Creación de una instancia de la clase Thread con el uso de la versión del constructor sobrecargado que recibe como argumento una instancia del delegado ThreadStart, y este encapsulando al método a ejecutar en el nuevo threadMetodoThread.
  • Línea 33: Invocación del método Start para iniciar la ejecución del método MetodoThread en el nuevo thread.
Compilación:


  1. csc /target:exe UsoDelegadoThreadStart.cs

Ejecución assembly:


  1. .\UsoDelegadoThreadStart.exe

> Prueba de ejecución (ideone.com).

> Prueba de ejecución (local):
Ejecución assembly UsoDelegadoThreadStart.exe
Figura 1. Ejecución assembly UsoDelegadoThreadStart.exe.

3.2 Delegado ParameterizedThreadStart

El delegado ParameterizedThreadStart [5] permite ejecutar un método sobre un thread. A diferencia de ThreadStart, ParameterizedThreadStart permite pasar datos al método que se ha de ejecutar en el thread. Esta es su firma:

public delegate void ParameterizedThreadStart(Object obj)

Descripción puntual:
  • Parámetros:
    • Object obj: Objeto contenedor de los datos para el método encapsulado por el delegado ParameterizedThreadStart.
Para poder iniciar la ejecución del método encapsulado por este delegado, es necesario que la instancia de Thread invoque al método Start [6].

Ejemplo de uso:

Archivo UsoDelegadoParameterizedThreadStart.cs [enlace alternativo]:



La clase UsoDelegadoParameterizedThreadStart (líneas 6-48) contiene los métodos:
  • Tarea1: (líneas 36-40) este método está declarado estático y contiene un parámetro de tipo object.
  • Tarea2: (líneas 43-47) este es un método de instancia. Igualmente, recibe un parámetro de tipo object.
En el código cliente (líneas 8-33) se crea una nueva instancia (línea 14) de la clase Thread. A su constructor le pasamos una instancia del delegado ParameterizedThreadStart, la cual encapsula el método Tarea1.


Más adelante, en la línea 21, invocamos al método Start al que le pasamos como argumento una literal entera. Este valor será usado como argumento por el método Tarea1.


Para probar el método Tarea2, creamos una instancia (línea 24de la clase UsoDelegadoParameterizedThreadStart. Esta instancia la usamos en la línea 28 para encapsular el método Tarea2 con el delegado ParameterizedThreadStart de forma implícita. Invocamos al método Start en la línea 32. Una vez invocamos este método el estado (cfr. Obtener el Estado de un Thread) del thread pasa de Unstarted a Starting.

Compilación:


  1. csc /target:exe UsoDelegadoParameterizedThreadStart.cs

Ejecución assembly:


  1. .\UsoDelegadoParameterizedThreadStart.exe

> Prueba de ejecución (ideone.com).

> Prueba de ejecución (local):
Ejecución assembly UsoDelegadoParameterizedThreadStart.exe
Figura 2. Ejecución assembly UsoDelegadoParameterizedThreadStart.exe.

4. Práctica: Código C#

Creemos un ejemplo con otros elementos de programa para demostrar la ejecución de un método sobre un nuevo thread:

Archivo C# MetodoEnNuevoThread.cs [enlace alternativo]:

Compilación:


  1. csc /target:exe MetodoEnNuevoThread.cs

Ejecución assembly:


  1. .\MetodoEnNuevoThread.exe

> Prueaba de ejecución (ideone.com).

> Prueba de ejecución (local):
Ejecución assembly MetodoEnNuevoThread.exe
Figura 3. Ejecución assembly MetodoEnNuevoThread.exe.

5. Conclusiones

Aprendimos a poner un método en ejecución en paralelo a través del uso de los delegados ThreadStart y ParameterizedThreadStart. Un método debe cumplir con cualquier de las dos firmas establecidas por estos delegados: el primero admite cero parámetros, y tipo de retorno void; el segundo admite un parámetro de tipo object y tipo de retorno void. Estos artefactos de la biblioteca base de clases de .NET Framework nos permiten controlar los momentos de ejecución de threads, a diferencia de un pool de threads que de forma automática se encarga de ejecutar los métodos. En la próxima receta nos centraremos en sincronizar la ejecución de varios threads con el uso de un monitor.

6. Glosario

  • Delegado
  • Ejecución
  • Hilo
  • Método
  • Multithreading
  • Thread

Literatura & Enlaces

[1]: Visual C# 2010 Recipes by Allen Jones and Adam Freeman. Copyright 2010 Allen Jones and Adam Freeman, 978-1-4302-2525-6.
[2]: Receta Multithreading No. 1-1 en C#: Cómo Crear un Thread | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2014/06/receta-multithreading-no-1-1-en-csharp-como-crear-un-thread.html
[3]: Receta No. 4-1 en C#: Ejecución de un Método sobre un Pool de Threads | OrtizOLón Software (xCSw) - http://ortizol.blogspot.com/2014/06/receta-no-4-1-en-csharp-ejecucion-de-un-metodo-sobre-un-pool-de-threads.html
[4]: ThreadStart Delegate (System.Threading) - http://msdn.microsoft.com/en-us/library/system.threading.threadstart(v=vs.110).aspx
[5]: ParameterizedThreadStart Delegate (System.Threading) - http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart(v=vs.110).aspx
[6]: Thread.Start Method (System.Threading) - http://msdn.microsoft.com/en-us/library/system.threading.thread.start(v=vs.110).aspx
[7]: Receta Multithreading en C# No. 1-5: Obtener el Estado de un Thread | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2014/07/receta-multithreading-en-csharp-no-1-5-obtener-el-estado-de-un-thread.html


J

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.