miércoles, 18 de junio de 2014

Receta Multithreading No. 1-1 en C#: Cómo Crear un Thread

Tabla de Contenido

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
3.1 Clase Thread
3.2 Delegado StartThread
3.3 Ejemplos
3.3.1 Crear un nuevo thread
3.3.2 Salida simultánea en pantalla de dos thread
3.3.3 Ejecución de un thread nuevo en WinForms
4. Práctica: Código Fuente C#
5. Conclusiones
6. Glosario
7. Literatura & Enlaces

0. Introducción

Esta es la primera receta que comprende el tratamiento exclusivo de multithreading en el lenguaje de programación C#. A partir de ahora vendrán publicaciones frecuentes sobre este tema tan importante por estos tiempos donde contamos con hardware y sistemas operativos muy potentes, capaces de ejecutar muchas aplicaciones en paralelo de forma eficiente y efectiva. En esta primera oportunidad, vamos a aprender cómo crear un thread, iniciarlo, y demostrar cómo podemos ejecutar tareas de forma simultánea en una aplicación de consola y otra compuesta por un formulario WinForms.

1. Problema

Mientras que en el método Main (o en cualquier otro proceso) ejecutamos una tarea en particular (e.g., invocación de un método, iteración de una colección, visualización de resultados en pantalla) de forma secuencial; ahora requerimos de una técnica que nos permita ejecutar tareas en segundo plano, y, simultáneamente, sin que se interrumpa mutuamente.

2. Solución

Podemos combinar el uso de la clase Thread (N:System.Threading) y el delegado System.Threading.StartThread. Estas construcciones lógicas nos va a permitir asociar un método con una instancia de un delegado, y empezar la ejecución simultánea con el thread principal (e.g., Main).

3. Discusión de la Solución

Ya mencioné que las construcciones Thread [6] y ThreadStart [3]. son las que nos permite crear nuevos threads. Ahora veamos cómo podemos combinarlas para crear métodos que se ejecuten de forma simultánea con otros procesos de nuestra aplicación.

3.1 Clase Thread

Esta clase la ubicamos en el namespace System.Threading. Esta clase está compuesta por cuatro constructores que se muestran en la Figura 1.
Constructores de la clase Thread
Figura 1. Constructores de la clase Thread.

Para la discusión y ejemplificación usaremos la versión que recibe como argumento una instancia de del delegado ThreadStart únicamente. Aquí está su firma [7]:

public Thread(ThreadStart start)

Descripción puntual:
  • ThreadStart start: La instancia del delegado ThreadStart se encarga de encapsular un método de instancia o estático que cumpla con su firma.
Una vez encapsulemos un método con ThreadStart, podemos proceder a la tarea más elemental sobre el thread recién creado, y es ejecutarlo a través del método Start [18]. (En los ejemplos demostraré su uso.)

3.2 Delegado StartThread

El delegado ThreadStart [3] 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»

3.3 Ejemplos

3.3.1 Crear un nuevo thread

En este primer ejemplo, crearemos una clase llamada NuevoThread con un método de instancia, el cual será pasada como argumento del constructor del delegado ThreadStart. Veamos:

Archivo de código fuente CrearNuevoThread.cs [enlace alternativo]:
En la líneas 16-19 se declara el método MetodoThread de la clase NuevoThread. Más adelante, en la línea 30 usaremos este método para pasarlo a la instancia del delegado como argumento del constructor de Thread:

Thread thread = new Thread( new ThreadStart(nt.MetodoThread));


Con el método Start, invocado en la línea 33, iniciamos la ejecución simultánea del método MetodoThread y Main. A pesar de que Main finalice su ejecución antes de MetodoThread, la ejecución de este último continuará hasta finalizar.

Compilación:


  1. csc /target:exe CrearNuevoThread.cs

Ejecución:


  1. .\CrearNuevoThread.exe

> Prueba de ejecución.

Resultado:

El método `Main` ha terminado. Presione Enter para terminar...
El valor de la variable `valor` es: 7

3.3.2 Salida simultánea de dos threads

Este ejemplo nos demostrará la salida de simultánea de dos métodos que se ejecutan en paralelo.

Archivo de código fuente UsoThread.cs [enlace alternativo]:

Observemos cómo en la línea 10 creamos una instancia del delegado ThreadStart a la que le pasamos una referencia del método estático ImprimirY (líneas 26-32). Enseguida, línea 11, iniciamos su ejecución.


Continuando, ejecutamos una serie de instrucciones sobre el ciclo for (líneas 16-19) de forma simultánea con el método ImprimirY. Estos nos va a generar una salida combinada de caracteres X e Y.

Compilación:


  1. csc /target:exe UsoThread.cs

Ejecución assembly:


  1. .\UsoThread.exe

> Prueba de ejecución.

Resultado:
Prueba de ejecución de UsoThread.exe
Figura 2. Prueba de ejecución de UsoThread.exe.

[Nota: La simultaneidad de la ejecución de dos o más métodos nos puede generar diferentes resultados por cada ejecución.]

3.3.3 Ejecución de un thread en WinForms

Ahora vamos a ver cómo podemos crear un thread en un formulario WinForms para ejecutar un proceso y su reporte en una barra de progreso de forma simultánea con el thread que carga el formulario principal.

Archivo de código fuente ThreadProgressBar.cs [enlace alternativo]:
Las secciones de código que nos interesa discutir se hayan en las líneas:
  • 62-86: Con el método TareaThread hacemos que la barra de progreso incremente y decremente (dependiendo del número aleatorio que se genere por cada iteración) de manera indeterminada.
  • 99-104: Cuando el formulario se carga, se crea inmediatamente un thread para asociar el método TareaThread con la tarea que se debe realizar en segundo plano. En la línea 102, se establece que el thread recién creado debe ejecutarse en segundo plano. Con thread.Start() (línea 103) iniciamos la ejecución thread de manera simultánea con el thread principal (el del formulario).
Compilación:

  1. csc /target:exe ThreadProgressBar.cs

Ejecución assembly:

  1. .\ThreadProgressBar.exe

Resultado:
Ejecución assembly ThreadProgressBar.exe
Figura 3. Ejecución assembly ThreadProgressBar.exe.

4. Práctica: Código Fuente C#

En este este ejemplo, de nuevo, se demuestra la ejecución simultánea de sentencias desde un thread principal y otro crearemos con el uso de la clase Thread:

Archivo de código fuente ImpresionNumeros.cs [enlace alternativo]:
Compilación:


  1. csc /target:exe ImpresionNumeros.cs

Ejecución assembly:


  1. .\ImpresionNumeros.exe

Resultado:
Prueba de ejecución de ImpresionNumeros.exe
Figura 4. Prueba de ejecución de ImpresionNumeros.exe.

5. Conclusiones

Con esta primera receta de multithreading en C# aprendimos a cómo crear un thread y ejecutar un método de manera simultánea con el thread principal (el que inicia la ejecución de la aplicación). Se hizo demostración de su funcionamiento sobre una aplicación de una consola, y otra basada en formularios WinForms.

6. Glosario

  • Método
  • Multithreading
  • Proceso
  • Simultaneidad
  • Thread

7. Literatura & Enlaces

[1]: Multithreading in C# 5.0 Cookbook by Eugene Agafonov. Copyright 2013 Eugene Agafonov, 978-1-84969-764-4.
[2]: Create New Thread [C#] - http://www.csharp-examples.net/create-new-thread/
[3]: ThreadStart Delegate (System.Threading) - http://msdn.microsoft.com/en-us/library/system.threading.threadstart.aspx
[4]: How to create a thread by using Visual C# - http://support.microsoft.com/kb/815804/en
[5]: Threading in C# - Free E-book - http://www.albahari.com/threading/
[6]: Thread Class (System.Threading) - http://msdn.microsoft.com/en-us/library/system.threading.thread(v=vs.110).aspx
[7]: Thread Constructor (ThreadStart) (System.Threading) - http://msdn.microsoft.com/en-us/library/xx3ezzs2(v=vs.110).aspx
[8]: Thread.Start Method (System.Threading) - http://msdn.microsoft.com/en-us/library/system.threading.thread.start(v=vs.110).aspx


S

No hay comentarios:

Publicar un comentario

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