jueves, 31 de julio de 2014

Receta Multithreading en C# No. 1-9: Sincronización con la Palabra Clave lock

Tabla de Contenido

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

0. Introducción

Por medio de esta receta multithreading en C# aprenderemos a utilizar la palabra clave lock, la cual es útil para implementar el mecanismo de acceso sincrónico excluyente a una región de código que represente un recurso compartido (.e.g., escritura de archivo). El ejemplo en la sección 4 nos demostrará la diferencia entre una clase sincronizada y una no sincronizada.

1. Problema

Diseñar o implementar un mecanismo de acceso seguro y consistente a datos compartidos por múltiples threads en ejecución.

2. Solución

El lenguaje de programación C# cuenta con la palabra clave lock. Esta construcción sintáctica y semántica permite definir una región o bloque de código (sección crítica).

3. Discusión de la Solución

En C# la palabra clave lock se utiliza siguiendo esta sintaxis:

lock(obj)
{
// Sección crítica
}

A destacar:
  • obj: Representa la instancia de bloqueo. Esta instancia de bloqueo puede ser de cualquier tipo, generalmente se recomienda Object. Además, y como advierten en [2], no se recomienda usar:
    • lock(this): debido a que this puede ser accedido por una función pública.
    • lock(typeof(MyType)): ídem al caso anterior.
    • lock("cadenaBloqueo"): un objeto string pueden ser accedido o usado desde cualquier otro proceso o ubicación.
  • El comentario // Sección crítica se refiere al conjunto de instrucciones que estarán protegidas y disponibles para acceso exclusivo por un thread.
Vale resaltar la recomendación hallada en [2]:
«Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances.»
Como medida constante de todas las recetas, escribiremos un ejemplo de uso para aterrizar este breve teoría vista hasta aquí.

Ejemplo de uso:

En la línea 11 declaramos la instancia de tipo Object que nos servirá de objeto de bloqueo para el acceso concurrente a la sección crítica definida en las líneas 34-48. Dentro del método Retirar usamos la palabra clave lock para encerrar el conjunto de instrucciones que se serán ejecutadas por un sólo thread al unísono. El contenido del método RealizarTransaccion crea hasta 100 transacciones por cada thread.

Compilación:


  1. csc /target:exe Banco.cs

Ejecución assembly:


  1. .\Banco.exe




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

4. Práctica: Código C#

Afiancemos nuestro conocimiento sobre el uso y aplicación de la palabra clave lock para alcanzar el mecanismo de exclusión mutua con este nuevo ejemplo (adaptado de [1]).

Este ejemplo incluye dos clases. A saber:
  • ContadorBasico (líneas 74-91): Esta clase se caracteriza por carecer de sincronización en los métodos abstractos implementados. Esto va ocasionar que se libere una carrera por acceso a a decrementar (línea 89) e incrementar (línea 84) y se generen resultados inconsistentes al ejecutar múltiples threads sobre los métodos en cuestión. (Ver prueba de ejecución.)
  • ContadorSincronizado (líneas 94-119): A diferencia de la clase anterior, esta implementa el mecanismo de sincronización de exclusión mutua a través del acceso controlado a la propiedad (Cuenta) que lleva el registro de los incrementos y decrementos realizados por los threads en ejecución.
Compilación:

  1. csc /target:exe Contador.cs

Ejecución assembly:

  1. .\Contador.exe


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

5. Artefactos

Enlaces de descarga de los artefactos producidos en el desarrollo de esta receta:

6. Conclusiones

Hemos comprendido el uso y utilidad de la palabra clave lock para implementar el mecanismo de sincronización basado en exclusión mutua. El ejemplo en la sección 4 nos demostró que una región o sección de código que carezca de este mecanismo es propensa a generar resultados inconsistencias sobre los datos. Para la próxima receta multithreading trabajeremos con la clase Monitor.

7. Glosario

  • Acceso seguro
  • Exclusión mutua
  • Palabra clave
  • Sección crítica
  • Sincronización
  • Thread

Literatura & Enlaces

[1]: Multithreading in C# 5.0 Cookbook by Eugene Agafonov. Copyright 2013 Eugene Agafonov, 978-1-84969-764-4.
[2]: lock Statement (C# Reference) - http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx
[3]: C# Lock Statement - http://www.dotnetperls.com/lock


J

No hay comentarios:

Publicar un comentario

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