lunes, 6 de julio de 2015

Receta Multithreading en C# No. 2-4: Envío de Mensajes entre Threads

Índice

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

0. Introducción

Nueva receta C# multithreading en la que entenderemos cómo podemos pasar mensajes entre diferentes threads. Veremos la construcicón AutoResetEvent; con objetos de esta clase podemos enviar notificaciones (mensajes) entre uno o más threads en ejecución.

1. Problema

Requerimos conocer un método para el envío de mensajes entre diferentes threads.

2. Solución

La BCL de .NET Framework ofrece la clase AutoResetEvent que facilita el envío de notificaciones a un thread que espera a que un evento ocurra para ejecutar una eventual operación.

3. Discusión de la Solución

3.1 Clase AutoResetEvent

La clase AutoResetEvent [2] notifica a los threads en espera a ser atentidos (uno por uno) o acceder a una región de código (región crítica) compartido, que un evento ha ocurrido y así continuar con la ejecución del proceso. Como explican en [3] este tipo de gestión de la sincronización se analoga al funcionamiento de un torniquete (ver imágenes). Así:
  1. Permitir el paso de una sola persona en un momento dado.
  2. Las personas que están detrás, deben esperar a que el torniquete esté libre para pasar: WaitOne.
  3. Y, se debe pasar o insertar el tiquete para continuar: Set.
En la Figura 1 [3] queda mejor descrito este proceso.

Funcionamiento de la clase AutoResetEvent
Figura 1. Funcionamiento de la clase AutoResetEvent [3].
En esta descripción pictórica, los threads Thread1Thread2, y Thread3 invocan al método WaitOne para iniciar la espera a que desde otro thread se invoque el método Set. Cada vez que se invoque este método, uno de los threads pasará por el torniquete.


Para demostrar uso, creemos un ejemplo que esté compuesto por una instancia de esta clase y el uso de los métodos WaitOne y Set:

Ejemplo de uso:

Archivo C# UsoAutoResetEvent.cs [enlace alternativo]:

En la línea 11 creamos una instancia de AutoResetEvent a la que le pasamos false a su constructor para indicar que no se invocará ninguna señal al inicio de instanciación. Más adelante, en la línea 15 creamos un nuevo thread y lo iniciamos inmediatamente:

new Thread (ProcesoEspera).Start ();


Al método Main lo ponemos en espera durante un segundo y medio (1500ms). Mientras que por otro lado, el método ProcesoEspera se haya en ejecución, en la línea 24 se muestra un mensaje en la salida estándar sobre el estado actual de ejecución del thread, o más precisamente, el punto que ha alcanzado su ejecución precisamente al invocar al método WaitOne:

waitHandle.Set();


Cuando se genera la señal, línea 19, en el método Main, el hilo de ejecución asociado al método ProcesoEspera continua su ejecución y se muestra en la salida estándar el mensaje de la línea 26.

En la Figura 2 [5] se describe pictóricamente todo el flujo de ejecución para este ejemplo.
Flujo de ejecución assembly UsoAutoResetEvent.exe
Figura 2. Flujo de ejecución assembly UsoAutoResetEvent.exe.
Compilación:


  1. csc /target:exe UsoAutoResetEvent.cs

Ejecución assembly:


  1. .\UsoAutoResetEvent.exe

Prueba de ejecución (ideone.com).

> Prueba de ejecución (local):
Ejecución assembly UsoAutoResetEvent.exe
Figura 5. Ejecución assembly UsoAutoResetEvent.exe.

4. Práctica: Código C#

Para afianzar nuestro conocimiento práctico de esta receta, creemos un ejemplo más:


Operaciones efectuadas sobre este código:
  • Líneas 10, y 11: Creación de objetos AutoResetEvent para para la generación de señalas de bloqueo y desbloqueo entre threads.
  • Línea 17: Creación un nuevo thread.
  • Línea 18: Inicio del thread recién creado.
  • Línea 20: El thread Main muestra el primer mensaje en pantalla anunciando que el nuevo thread se haya en ejecución.
  • Línea 42: El thread nuevoThread muestra mensaje de inicio de proceso largo.
  • Línea 43: Espera que simula la ejecución por 10 segundos el nuevo thread -nuevoThread-.
  • Línea 22: Desde el thread Main se envía señal de bloqueo al thread nuevoThread.
  • Línea 44: El thread nuevoThread muestra mensaje de que ha finalizado la primera tarea.
  • Línea 47: Con la invocación de Set sobre el objeto eventoSecundario envíamos señal de desbloqueo al thread nuevoThread: indicado en la línea 22.
  • ...
Para evitar la verbosidad en la descripción de este código, añado diagrama de threads análogo al presentado en la Figura 2:
Envío de Mensajes entre Threads
Figura 2. Envío de Mensajes entre threads.
Compilación:

  1. csc /target:exe EnvioNotificacionesThreads.cs

Ejecución assembly:

  1. .\EnvioNotificacionesThreads.exe


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

5. Conclusiones

Exploramos los básicos de la clase AutoResetEvent para controlar el envío de señales de bloqueo y desbloqueo entre threads. Se reconoció que los métodos WaitOne y Set permiten bloquear o desbloquear threads a través del envío de señales de distintas locaciones de procesos de ejecución simultánea. La próxima receta C# multithreading elaboraremos los pasos necesarios para trabajar con la clase ManualResetEventSlim para el envío de mensajes (señales) entre threads de manera más sencilla.

6. Glosario

  • Bloqueo
  • Desbloqueo
  • Mensaje
  • Notificación
  • Señal
  • Thread

7. Literatura & Enlaces

[1]: Multithreading in C# 5.0 Cookbook by Eugene Agafonov. Copyright 2013 Eugene Agafonov, 978-1-84969-764-4.
[2]: AutoResetEvent Class (System.Threading) - https://msdn.microsoft.com/en-us/library/system.threading.autoresetevent(v=vs.110).aspx
[3]: Multithreading in .Net and C#: EventWaitHandler: AutoResetEvent and ManualResetEvent - http://multithreads.blogspot.com/2007/09/eventwaithandler-autoresetevent-and.html
[4]: ManualResetEvent Class (System.Threading) - http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent%28v=vs.110%29.aspx
[5]: Threading in C# - Part 2 - Basic Synchronization - http://www.albahari.com/threading/part2.aspx


J

No hay comentarios:

Publicar un comentario

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