jueves, 9 de julio de 2015

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

Índice

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

0. Introducción

En la receta multithreading anterior (2-4) usamos la clase AutoResetEvent para el envío de mensajes o notificaciones entre threads. Esta operación nos permitió activar o desactivar la continuación de la ejecución de las tareas de un proceso asociado a un thread a través del uso de los miembros disponibles en esa misma clase: Set, y WaitOne. Ahora estudiáremos cómo usar la clase ManualResetEventSlim para enviar mensajes múltiples threads.

1. Problema

Requerimos un método para el envío de mensajes o notificaciones a múltiples threads.

2. Solución

Con la clase ManualResetEventSlim podemos enviar una notificación a un proceso para que múltiples threads continúen ejecutando las tareas (instrucciones) definidas en tal proceso.

3. Discusión de la Solución

La clase ManualResetEventSlim [2] provee una versión reducida de ManualResetEvent [4]. Esta última la hemos tratado con detalle en Receta C# No. 4-8: Sincronizar la Ejecución de Múltiples Threads usando un Evento (lectura que sugiero para facilitar la comprensión de ManualResetSlim).

A diferencia de AutoManualReset, ManualResetSlim funciona análogamente como una puerta por donde pueden transitir múltiples threads. En la Figura 1 se muestra el análogo entre estos dos enfoques de control y de envío de mensajes/notificaciones en la ejecución de múltiples threads.
AutoResetEvent vs. ManualResetEvent
Figura 1. AutoResetEvent vs. ManualResetEvent [6].
A la derecha vemos la analogía de un torniquete con la clase AutoResetEvent: un único thread puede pasar por el torniquete (continuar su ejecución); mientras, que la clase ManualResetEvent es similar a una puerta amplia (izquierda): múltiples threads pueden pasar al mismo tiempo. La clase ManualResetEventSlim opera similar a esta última pero de forma más flexible. Esta flexibilidad y optimización es para tiempos de espera más cortos para los threads.

4. Práctica: Código C#

En este ejemplo controlaremos la ejecución de 3 threads que tendrán asociado un proceso. Desde el thread Main enviaremos las señales de suspensión y continuación de la ejecución de los threads según sea necesario.


En la línea 12 creamos un objeto ManualResetEventSlim para el control de señales de suspensión y continuación de la ejecución de threads. Notar que la instanciación de este objeto empieza sin ser notificado: argumento false. En las líneas 19-21 creamos tres objetos Thread a los cuales asignamos la ejecución del método Proceso.

Una vez creados los tres threads anteriores, pasamos a iniciar su ejecución: líneas 24-26. En la salida estándar se mostrará el mensaje de inicio de cada thread. Cada thread iniciará un tiempo de espera acorde al valor del argumento tiempoEspera: línea 61.

Ahora, desde la línea 32, en Main, envíamos la señal de continúación: evento.Set(). Pasados dos segundos, Thread.Sleep(FromSeconds(2)) (precisamente en la línea 34), bloqueamos la ejecución hasta que se invoque nuevamente el método Set(). Los threads que ya han superado el tiempo de espera en la línea 61 terminarán su ejecución, los restantes seguirán esperando hasta que se vuelva a enviar una nueva señal de continuación: línea 42.

En la Animación 1 se puede apreciar mejor el efecto que tiene la invocación de los métodos:
  • Reset
  • Set, y 
  • Wait.
Compilación:


  1. csc /target:exe NotificacionMultiplesThreads.cs


Ejecución assembly:


  1. .\NotificacionMultiplesThreads.exe

> Prueba de ejecución (local):
Ejecución assembly NotificacionMultiplesThreads.exe
Animación 1. Ejecución assembly NotificacionMultiplesThreads.exe.

5. Conclusiones

Estudiamos la clase ManualResetEventSlim y reconocimos que nos es útil para controlar el flujo de ejecución de múltiples threads. Los métodos Reset, Set, y Wait son los miembros que permiten:
  • bloquear un conjunto de threads
  • desbloquear un conjunto de threads, y 
  • bloquear un thread en particular durante un período indeterminado de tiempo.
respectivamente.

Entendimos a la clase ManualResetEventSlim, como una puerta amplia por donde pueden pasar (ejecutarse) múltiples threads.

La próxima receta multithreading la dedicaremos a estudiar la clase CountDownEvent que como veremos es útil para esperar hasta que cierto número de operaciones se hayan ejecutado.

6. Glosario

  • Evento
  • Método
  • 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]: ManualResetEventSlim Class (System.Threading) -
https://msdn.microsoft.com/en-us/library/system.threading.manualreseteventslim(v=vs.110).aspx
[3]: Threading in C# - Part 2 - Basic Synchronization -
http://www.albahari.com/threading/part2.aspx#_ManualResetEvent
[4]: ManualResetEvent Class (System.Threading) -
https://msdn.microsoft.com/en-us/library/system.threading.manualresetevent(v=vs.110).aspx
[5]: Receta C# No. 4-8: Sincronizar la Ejecución de Múltiples Threads usando un Evento - http://ortizol.blogspot.com/2014/07/receta-c-no-4-8-sincronizar-la-ejecucion-de-multiples-threads-usando-un-evento.html
[6]: Multithreading in .Net and C#: EventWaitHandler: AutoResetEvent and ManualResetEvent - http://multithreads.blogspot.com/2007/09/eventwaithandler-autoresetevent-and.html


J

No hay comentarios:

Publicar un comentario

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