miércoles, 10 de septiembre de 2014

Receta C# No. 4-14: Acceso Concurrente con Múltiples Threads a una Colección de Modo Seguro

Í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

Acceder al contenido de una instancia de una colección representa otra técnica a conocer cuando debemos llevar a cabo manipulaciones a través de múltiples threads. Estas modificaciones deben realizarse de modo seguro de tal modo que se evite la corrupción o daño sobre los datos de objetos ahí contenidos. En esta receta C# entenderemos el proceso de acceso seguro al contenido de una instancia de una colección.

1. Problema

Se requiere implementar un método de acceso concurrente seguro por parte de múltiples threads al contenido de una colección.

2. Solución

De acuerdo con [1], para sincronizar el acceso concurrente al contenido de una colección se requiere el uso de la sentencia lock.

3. Discusión de la Solución

Los nombres de espacio especializados en colecciones:
  • System.Collections,
  • System.Collections.Specialized, y
  • System.Collections.Generic
de forma nativa proveen soporte para la lectura concurrente de una instancia de cualquier de las clases contenidas en estos nombres de espacio por parte de múltiples threads. Hasta aquí todo bien. Sin embargo, hay que considerar que a diferencia de la lectura del contenido de una colección, la escritura sí que puede representar un caso más complejo y propenso a problemas cuando de modificación concurrente del contenido de la colección se trata. La razón de esto, la encontramos en [1]:
«This is because the operating system can interrupt the actions of the thread while modifications to the collection have been only partially applied. This leaves the collection in an indeterminate state, which will almost certainly cause another thread accessing the collection to fail, return incorrect data, or corrupt the collection.»
Por otra parte, y en relación a lo anterior, clases como:
  • ArrayList
  • Hashtable
  • Queue
  • SortedList, y 
  • Stack
del nombre de espacios System.Collections poseen el método Synchronized para generar una representación sincronizada de la instancia original. Veamos un ejemplo concreto de este método:

Archivo C# UsoSynchronized.cs [enlace alternativo]:

En la línea 11 creamos una instancia de la clase Queue, y en las líneas 14-17 localizamos datos sobre la cola con el método Enqueue. Sobre la línea 21 invocamos al método static Synchronized para obtener la representación sincronizada de la instancia de Queue original (q). En los dos métodos Console.WriteLine simplemente mostramos el estados de los dos objetos: q y qSincronizado.

Compilación:


  1. csc /target:exe UsoSynchronized.cs

Ejecución assembly:


  1. .\UsoSynchronized.exe

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

> Prueba de ejecución (local):
Ejecución assemly UsoSynchronized.exe
Figura 1. Ejecución assemly UsoSynchronized.exe.

Vale destacar la nota que se hace en [1] acerca de la introducción de clases con capacidades de acceso concurrente sobre el nombre de espacios System.Collections.Concurrent:
«.NET 4.0 introduces a set of efficient thread-safe collections in the System.Collections.Concurrent namespace that can be used.»

4. Práctica: Código C#

Veamos un ejemplo con el uso de lock para asegurar el acceso concurrente por parte de múltiples threads a una colección de tipo ArrayList:

Archivo C# lockColecciones.cs [enlace alternativo]:

A destacar las líneas 39-52: método AccederLista. Este método en su interior realiza un bloqueo (exclusión mutua) sobre los threads que intentan acceder a la región (líneas 43-50) cuando un thread ya lo ha hecho y tomado el poder de la región mencionada. El código de la región crítica muestra el contenido de un objeto ArrayList de forma secuencial. 10 (líneas 31-36) son los threads que intentarán apoderarse de esta región.

Compilación:


  1. csc /target:exe lockColecciones.cs

Ejecución assembly:


  1. .\lockColecciones.exe

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

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

5. Conclusiones

De manera básica se ha introducido la noción de acceso concurrente al contenido de una colección por parte de múltiples threads. Entendimos que .NET Framework cuenta con colecciones especializadas para acceso concurrente en el nombre de espacios System.Collections.Concurrent. Por otra parte conocimos el método static Synchronized adecuado para crear representaciones seguras de colecciones del nombre de espacio System.Collections. Al final creamos un ejemplo con el uso de la palabra clave lock para demostrar el control concurrente sobre el contenido de un objeto ArrayList. En la siguiente receta aprenderemos a iniciar una aplicación en un nuevo proceso.

6. Glosario

  • Acceso concurrente
  • ArrayList
  • Colección
  • Región crítica
  • Thread

7. 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]: Queue.Synchronized Method (System.Collections) - http://msdn.microsoft.com/en-us/library/vstudio/system.collections.queue.synchronized(v=vs.100).aspx


J

No hay comentarios:

Publicar un comentario

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