jueves, 23 de julio de 2015

Receta Multithreading en C# No. 3-4: Cancelación Ejecución de una Operación Asincrónica

Índice

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
3.1 Estructura CancellationToken
3.2 Clase CancellationTokenSource
4. Práctica: Código C#
4.1 Práctica No. 1: Mediciones
4.2 Práctica No. 2: Enfoques de cancelación
5. Conclusiones
6. Glosario
7. Literatura & Enlaces

0. Introducción

Cuarta receta de la serie de recetas C# dedicada a pool de threads. En esta oportunidad vamos a conocer el proceso de cancelación de un thread que esté ejecutando una operación asincrónica en el pool de threads. Deberemos de usar otras de las construcciones disponibles en el namespace System.Threading: la estructura CancellationToken y la clase CancellationTokenSource.

1. Problema

Debemos de cancelar una operación asincrónica ejecutada por uno de los threads del pool de threads.

2. Solución

En conjunto, el struct CancellationToken y la clase CancellationTokenSource facilitan la cancelación de la ejecución de una operación asincrónica.

3. Discusión de la Solución

3.1 Estructura CancellationToken

Con CancellationToken [2] (System.Threading) podemos generar una notificación para que un conjunto de operaciones asincrónicas se cancelen.

El diseño de esta estructura permite que una notificación de cancelación se propague en conjunto de threads, en un pool de thread, o en objetos Task [2].

Para lograr esto debemos seguir estos pasos:
  1. Crear un objeto de la clase CancellationTokenSource
  2. Obtener un token de cancelación desde la propiedad CancellationSource.Token
  3. Pasar este token a los diferentes threads, objetos Task, u operaciones asincrónicas, para que desde éstos se invoce la propiedad IsCancellationRequested, se genere la excepción OperationCanceledException [4], o se invoque un callback.
  4. Invocar el método Cancel de la instancia CancellationTokenSource para propagar la notificación de cancelación.

3.2 Clase CancellationTokenSource

Esta clase constituye parte de la solución descrita en la sección anterior para emitir una notificación de cancelación de ejecución de una operación asincrónica. La clase CancellationTokenSource [3] está declarada en el namespace System.Threading.

Continuando, esta clase implementa el patrón Disposable con lo cual podríamos incluir un quinto paso (respecto a la lista previa) que consiste en la invocación del método Dispose para la liberación de los recursos utilizados por un objeto de esta clase.

4. Práctica: Código C#

4.1 Práctica No. 1

En esta primera demostración (adaptación de [3]) se simulará la recolección de medidas de 10 diferentes instrumentos. Cuando la medición sea igual a 0 (cero), significa que el instrumento ha fallado en la toma de una de las mediciones y por lo tanto la operación debe cancelarse y el cómputo del promedio no será tenido en cuenta.

Empezamos declarando un objeto CancellationTokenSource en la línea 17 para la emisión de notificaciones de cancelación de tareas asincrónicas. Obtenemos el token de cancelación (línea 19). En la línea 26 creamos una lista con objetos Task, y éstos a la vez con un arreglo de enteros de 32 bits para contener cada una de las mediciones de un instrumento (tarea).


Creamos un objeto TaskFactory [5] (línea 29) al cual pasamos como argumento el token obtenido en la línea 19. Esto nos va a permitir desde el interior de una instancia de Task emitir la notificación de cancelación.

En el ciclo for (líneas 32-63) se crean cada una de las tareas (instrumentos de medición) y se toman las 10 mediciones por cada instrumento. En caso de que una de las mediciones de cualquier instrumento sea igual a cero (línea 49) se invoca el método Cancel del objeto cts:CancellationTokenSource (línea 52) y se interrumpe la toma de las demás mediciones. En caso de que la medición sea satisfactoria, se agrega al arreglo mediciones (línea 58). Finalmente, en la línea 61 se retorna el arreglo de mediciones como resultado para la tarea.


En el bloque try (líneas 65-89) ocurren las siguientes operaciones: 
  • Línea 69: Invocación del método ContinueWhenAll de Factory para asegurar que el promedio se pueda calcular cuando todos los instrumentos (tareas) han obtenido las mediciones especificadas (10 por cada uno).
  • Líneas 77-84: Se calcula el promedio de todas las mediciones de todos los instrumentos.
  • Línea 88: Se muestra en la salida estándar el cómputo del promedio.
En el bloque catch se describen cada una de las excepciones producidas por la falla de un instrumento a la hora de tomar la medida.


En el bloque finally se invoca al método Dispose para liberar los recursos demandados por el objeto cts.


Compilación: 


  1. csc /target:exe Medicion.cs


Ejecución assembly


  1. .\Medicion.cs

> Prueba de ejecución: http://ideone.com/RE1Pqf

> Prueba de ejecución: 
Ejecución assembly Medicion.exe
Animación 1. Ejecución assembly Medicion.exe.

4.2 Práctica No. 2

Ahora pasemos a crear otra aplicación consola para demostrar tres enfoques distintos de cancelación de una operación asincrónica.

Método OperacionAsincronica1(CancellationToken)
  • Línea 64: Muestra mensaje de inicio de la operación asincrónica número 1.
  • Líneas 66-75: Ciclo for para simular una tarea larga en esta operación asincrónica: 
    • Línea 68: Consulta la propiedad del objeto CancellationToken en determinación si la operación asincrónica ha sido cancelada.
    • Línea 70: En caso de que la operación asincrónica haya sido cancelada, se muestra un mensaje advirtiéndolo.
    • Línea 74: Se genera una espera por cada iteración del ciclo.
  • Línea 77: Si no se generó ninguna interrupción se muestra un mensaje de satisfacción en la salida estándar.
Método OperacionAsincronica2(CancellationToken):
  • Líneas 82-93: Bloque try que supervisa la generación de excepción por la activación del método ThrowIfCancellationRequested (línea 88).
    • Línea 92: Si no se generó ninguna interrupción se muestra mensaje de satisfacción en la salida estándar.
  • Líneas 94-97: Bloque catch que captura la excepción generada por la activación de la cancelación.
    • Línea 96: Muestra mensaje en la salida estándar advirtiendo que se canceló la ejecución de la operación asincrónica.
Método OperacionAsincronica3(CancellationToken)
  • Línea 102: Valor lógico centinela.
  • Línea 104: Registro de callback en caso de que se emita una notificación de cancelación en esta operación asincrónica.
  • Línea 110: Se valida la activación de la señal.
    • Línea 112: Muestra mensaje cuando la operación asincrónica ha sido activada.
Desde el método Main (líneas 10-60) se utilizan los diferentes mecanismos de emisión de notificación de cancelación a las tres operaciones asincrónicas descritas.

Compilación: 

  1. csc /target:exe CancelacionOperacionAsincronica.cs

Ejecución assembly

  1. .\CancelacionOperacionAsincronica.exe

> Prueba de ejecución: http://ideone.com/96iFhN

> Prueba de ejecución: 
Ejecución assembly CancelacionOperacionAsincronica.exe
Animación 2. Ejecución assembly CancelacionOperacionAsincronica.exe.

5. Conclusiones

Ha quedado demostrado que en C# contamos con los mecanismos de cancelación de una operación asincrónica que se ejecute en un pool de threads. Gracias a los diferentes enfoques de cancelación disponibles (i.e., comprobación de propiedad IsCancellationRequested, generación de la excepción OperationCanceledException, e invocación de callback) podemos efectuar una implementación de cancelación adaptada a las características particulares de ejecución de una operación asincrónica.


En la próxima receta multithreading C# estudiáremos cómo introducir un mecanismo de espera en un pool de threads.

6. Glosario

  • Cancelación
  • Excepción
  • Notificación
  • Operación asincrónica
  • Pool
  • Thread
  • Token

7. Literatura & Enlaces

[1]: Multithreading in C# 5.0 Cookbook by Eugene Agafonov. Copyright 2013 Eugene Agafonov, 978-1-84969-764-4.
[2]: CancellationToken Structure (System.Threading) - https://msdn.microsoft.com/en-us/library/system.threading.cancellationtoken(v=vs.110).aspx
[3]: CancellationTokenSource Class (System.Threading) - https://msdn.microsoft.com/en-us/library/system.threading.cancellationtokensource(v=vs.110).aspx
[4]: OperationCanceledException Class (System) - https://msdn.microsoft.com/en-us/library/system.operationcanceledexception(v=vs.110).aspx
[5]: TaskFactory Class (System.Threading.Tasks) - https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory(v=vs.110).aspx


V

No hay comentarios:

Publicar un comentario

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