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

martes, 29 de julio de 2014

Excepciones en C# - Parte 5: Ejemplos de Excepciones Comunes

Tabla de Contenido

0. Introducción
1. ArgumentException
2. ArgumentNullException
3. ARgumentOutOfRangeException
4. DivideByZeroException
5. IndexOutOfRangeException
6. InvalidCastException
7. InvalidOperationException
8. NullReferenceException
9. OverflowException
10. Conclusiones
11. Glosario
12. Literatura & Enlaces

0. Introducción

Quinta y última parte de la serie de artículos dedicados a la comprensión y tratamiento de excepciones en C#. En esta oportunidad vamos a realizar varios ejemplos (9, precisamente) acerca del uso de excepciones generadas en tiempo de ejecución. Todas estas excepciones (las que aquí trataremos) forman parte de la biblioteca base de clases de Microsoft .NET Framework. Entonces procedamos a desarrollar estos ejemplos para afianzar el conocimiento adquirido durante las 4 partes anteriores:



1. ArgumentException

La excepción ArgumentException se lanza cuando uno de los argumentos que se pasan a un método no es válido [3]. Para el lanzamiento de esta excepción, se recomienda pasar un mensaje a la instancia de esta excepción, que tenga significado tanto para el programador como para el usuario del código; esto con el fin de facilitar la interpretación y corrección de errores con mayor agilidad.

En [3] nos advierten que a partir de esta clase derivan otras dos:
  • ArgumentNullException: cuando el valor null es pasado como argumento a un método.
  • ArgumentOutOfRange: cuando el valor de un argumento excede un rango establecido para la lógica de un método.
las cuales trataremos más adelante con detalles de ejemplos y descriptivos.

Ejemplo de uso:

Cuando al método DividirPorDos (líneas 8-18) le pasamos un valor de argumento que no es divisible por dos (línea 12), en la línea 14 se crea y se lanza una instancia de la excepción ArgumentException. En el código cliente (líneas 20-35) tratamos esta excepción en el bloque try-catch de las líneas 25-34. Cuando se genera esta excepción, en pantalla mostramos un mensaje que señala la causa y el nombre del argumento que la generó (línea 33.

Compilación:


  1. csc /target:exe UsoArgumentException.cs

Ejecución assembly:


  1. .\UsoArgumentException.exe

Prueba de ejecución (ideone.com).

> Prueba de ejecución (local):
Ejecución aseembly UsoArgumentException.exe
Figura 1. Ejecución aseembly UsoArgumentException.exe.

2. ArgumentNullException

La excepción ArgumentNullException [4] se lanza cuando una referencia null es pasada a un método que no acepta este valor. Además, y de acuerdo con [4], esta excepción se genera cuando el programador o desarrollador ha efectuado una de estas operaciones:
  • Uno o varios de los argumentos que no aceptan referencias null, ha(n) sido asociado(s) con un valor de esta naturaleza. Para remediar este problema, lo único que hay que hacer es crear una instancia del objeto que se será pasado como argumento.
  • En una cadena de llamada a métodos, uno de ellos retorna una referencia null.
Ejemplo de uso:

De manera análoga al ejemplo de la sección 1, en este caso, el método, MostrarMensaje valida cuando el argumento mensaje contiene una referencia null (línea 12). La excepción es tratada en el bloque catch de las líneas 31-34.

Compilación:


  1. csc /target:exe UsoArgumentNullException.cs

Ejecución assembly:


  1. .\UsoArgumentNullException.exe

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

> Prueba de ejecución (local):
Ejecucón assembly UsoArgumentNullException.exe
Figura 2. Ejecucón assembly UsoArgumentNullException.exe.

3. ArgumentOutOfRangeException

La excepción ArgumentOutOfRangeException [5] se lanza cuando el valor de un argumenta está por fuera de los límites inferior y superior. Esta excepción asume que el argumento no contiene una referencia igual a null [5]. Por otro lado, la excepción ArgumentOutRangeException se usa recurrentemente por clases de los namespace System.Collections y System.IO; y también por la clase Array.

Ejemplo de uso:

Archivo C# UsoArgumentOutOfRangeException.cs [enlace alternativo]:

En el constructor (líneas 11-25) de la clase Invitado, se valida la edad del invitado; en caso de que esta sea menor o igual a 30, se lanza la excepción ArgumentOutOfRangeException, a la cual se añade la información sobre el parámetro con el valor inválido, y un mensaje indicativo del error o problema.


En el método Main se crea una instancia (línea 45) de Invitado con la edad por debajo del valor admitido.


Compilación:


  1. csc /target:exe UsoArgumentOutOfRangeException.cs

Ejecución assembly:


  1. .\UsoArgumentOutOfRangeException.exe

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

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

4. DivideByZeroException

La excepción DivideByZeroException [6] se lanza cuando se intenta dividir un número entero entre cero (0). A diferencia de los enteros, los números de punto flotante (i.e., float, double) no generan esta excepción en un intento de división entre cero. (Más información en [6].)

Ejemplo de uso:

Dentro del bloque try se intenta realizar una división entre cero, dado que la variable divisor tiene asignado el número cero (línea 10). Cuando esto ocurre, se genera la excepción DivideByZeroException, y se muestra un mensaje de error en pantalla (línea 18).

Compilación:


  1. csc /target:exe UsoDivideByZeroException.cs

Ejecución assembly:


  1. .\UsoDivideByZeroException.exe

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

> Prueba de ejecución (local):
Ejecución assembly UsoDivideByZeroException.exe
Figura 4. Ejecución assembly UsoDivideByZeroException.exe.

5. IndexOutOfRangeException

Para las estructuras de datos lineales, como los arreglo, esta excepción -IndexOutOfRangeException [7]- se genera en el intento de sobrepasar los límites inferior y superior del arreglo.

Ejemplo de uso:

En el bloque try (líneas 17-22) sobre el método WriteLine se hace uso del valor del indíce 5 para acceder al elemento en esa posición (el cual no existe, en este caso supera el límite superior del arreglo), y generará la excepción IndexOutOfRangeException.

Compilación:


  1. csc /target:exe UsoIndexOutOfRangeException.cs

Ejecución assembly:


  1. .\UsoIndexOutOfRangeException.exe

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

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

6. InvalidCastException

Los intentos fallidos de conversión implícita o explícita de tipos (e.g., interfaz, clase) generan la excepción InvalidCastException [8].

Ejemplos de uso:

Tenemos la jerarquía explicitada en las líneas 5 y 6: B hereda de A.


En la línea 14 creamos una instancia de A, luego, sobre la línea 22 intentamos de realizar una conversión explícita con el operador (), la cual falla debido a que la conversión en un tipo superior (superclase) a uno inferior (subclase) en la jerarquía de herencia no está permitida según los principios de programación orientada objetos.


Compilación:


  1. csc /target:exe UsoInvalidCastException.cs

Ejecución assembly:


  1. .\UsoInvalidCastException.exe

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

> Prueba de ejecución (local):
Ejecución assembly UsoInvalidCastException.exe
Figura 6. Ejecución assembly UsoInvalidCastException.exe.

7. InvalidOperationException

El intentar realizar una invocación de los métodos de instancia sobre una instancia cuyo estado actual es inválido, se lanza la excepción InvalidOperationException. El ejemplo más clásico, consiste en invocar un método sobre una variable cuya referencia actual es null.

Ejemplo de uso:

Creamos una instancia de StreamWriter en la línea 11; agregamos dos líneas al archivo: líneas 13 y 14. Decidimos cerrar el archivo: invocamos al método Close (línea 17). Dentro del bloque try hacemos el intento de agregar una nueva línea al archivo, pero falla, debido a que el archivo ha sido cerrado previamente, luego, se genera la excepción InvalidCastOperationException.

Compilación:


  1. csc /target:exe UsoInvalidOperationException.cs

Ejecución assembly:


  1. .\UsoInvalidOperationException.exe

> Prueba de ejecución:
Ejecución assembly UsoInvalidOperationException.exe
Figura 7. Ejecución assembly UsoInvalidOperationException.exe.

8. NullReferenceException

La excepción NullReferenceException [10] se lanza cuando se intenta acceder o manipular el estado de un variable que tiene asignada la referencia null.

Ejemplo de uso:

En la línea 12 definimos una variable de ArrayList, sin embargo le asignamos la referencia null. El hecho de intentar de invocar sobre el estado actual de esta variable, cualquier método generará la excepción NullReferenceException: línea 18.

Compilación:


  1. csc /target:exe UsoNullReferenceException.cs

Ejecución assembly:


  1. .\UsoNullReferenceException.exe

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

> Prueba de ejecución (local):
Ejecución assembly UsoNullReferenceException.exe
Figura 8. Ejecución assembly UsoNullReferenceException.exe.

9. OverflowException

Para operaciones aritméticas o de conversiones que sobrepasan los límites de memoria de tipos de datos (e.g., enteros).

Ejemplo de uso:

La operación de suma en la línea 12 genera la excepción OverflowException debido a que se sobrepasa la capacidad de almacenamiento para el tipo de entero de 32 bits: Int32.

Compilación:


  1. csc /target:exe UsoOverflowException.cs

Ejecución assembly:


  1. .\UsoOverflowException.exe

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

> Pueba de ejecución (local):
Ejecución assembly UsoOverflowException.exe
Figura 9. Ejecución assembly UsoOverflowException.exe.

10. Conclusiones

Evidentemente en la biblioteca base de clases del Framework .NET existen centenares de clases de excepción especializadas para situaciones de error o excepcionales, sin embargo aquí he mencionado solo nueve de ellas; y todo esto tiene como invitación a considerar el uso de este tipo de elementos de programa en nuestros desarrollos ya sea para propósitos académicos y/o comerciales, debido a que las soluciones de software construidas serán más tolerantes a fallas o errores en su ejecución. Con esta última parte damos fin a la serie de excepciones en C#, empero, en futuras entregas de artículos, recetas, aplicaciones, &c., seguiremos resaltando su uso en las situaciones donde sea necesario o indispensable.

11. Glosario

  • Arreglo
  • Casting
  • Conversión
  • Excepción
  • Exception
  • Explícita
  • Implícita
  • Índice

12. Literatura & Enlaces

[1]: C# 5.0 in a Nutshell by Joseph Albahari and Ben Albahari. Copyright 2012 Joseph Albahari and Ben Albahari, 978-1-449-32010-2.
[2]: List down the commonly used types of exceptions in .Net? - http://www.c-sharpcorner.com/Interviews/answer/7280/list-down-the-commonly-used-types-of-exceptions-in-net
[3]: ArgumentException Class (System) - http://msdn.microsoft.com/en-us/library/system.argumentexception%28v=vs.110%29.aspx
[4]: ArgumentNullException Class (System) - http://msdn.microsoft.com/en-us/library/system.argumentnullexception%28v=vs.110%29.aspx
[5]: ArgumentOutOfRangeException Class (System) - http://msdn.microsoft.com/en-us/library/system.argumentoutofrangeexception%28v=vs.110%29.aspx
[6]: DivideByZeroException Class (System) - http://msdn.microsoft.com/en-us/library/system.dividebyzeroexception%28v=vs.110%29.aspx
[7]: IndexOutOfRangeException Class (System) - http://msdn.microsoft.com/en-us/library/system.indexoutofrangeexception%28v=vs.110%29.aspx
[8]: InvalidCastException Class (System) - http://msdn.microsoft.com/en-us/library/system.invalidcastexception%28v=vs.110%29.aspx
[9]: InvalidOperationException Class (System) - http://msdn.microsoft.com/en-us/library/system.invalidoperationexception%28v=vs.110%29.aspx
[10]: NullReferenceException Class (System) - http://msdn.microsoft.com/en-us/library/system.nullreferenceexception%28v=vs.110%29.aspx
[11]: OverflowException Class (System) - http://msdn.microsoft.com/en-us/library/system.overflowexception%28v=vs.110%29.aspx


J

sábado, 26 de julio de 2014

Pregunta C# (3 de 20): ¿Cuál es la Diferencia entre String y string?

Tabla de Contenido

0. Introducción
1. Documentación
1.1 String
1.2 string
2. String y string en Visual Studio y Notepad++
2.1 Visual Studio
2.2 Notepad++
2.3 Otros editores
3. Enumeración de Diferencias Sobresalientes
4. Ejemplo de Uso
5. Recursos
6. Conclusiones
7. Glosario
8. Literatura & Enlaces

0. Introducción

Tercera pregunta (de veinte) C# en la que vamos a comprender la(s) diferencia(s) entre String y string. Para lograrlo, estudiáremos las convenciones estándar de código C#. Distinguiremos, igualmente, la diferencia visual (impresora estética) entre estas dos representaciones en el IDE Visual Studio y Notepad++. Los ejemplos de código C# nos demostrarán de forma fehaciente las coincidencias que existen con los tipos definidos en la biblioteca base de tipos de .NET Framework. ¡Manos a la obra!

1. Documentación

Veamos cómo estos dos tipos, String y string, se hayan documentados en MSDN.

1.1 String (descripción convencional de tipos)

La clase String, de acuerdo con [3], representa un texto como una serie de caracteres Unicode. Esta clase hereda directamente del tipo base Object. En [3], encontramos que al igual que muchos tipos de la biblioteca base de clases de .NET Framework, la descripción documental para este tipo se expone con las categorías convencionales, como:
  • Constructores
  • Campos
  • Métodos
  • Operadores
  • Propiedades
Miembros String en MSDN
Figura 1. Miembros String en MSDN.

1.2 string (referencia C#)


En la documentación de MSDN encontramos que este tipo de dato es descrito como una palabra clave o constructo del lenguaje C#:
Palabra clave string en MSDN
Figura 2. Palabra clave string en MSDN.
Evidentemente, la diferencia en este apartado documental consiste en que String es tratado como un tipo de la biblioteca base de clase (BCL, por sus siglas en inglés), mientras que string es considerado uno de los constructos propios del lenguaje de programación C#.

2. String y string en Visual Studio y Notepad++

Antes de pasar a la enumeración de las diferencias sobresalientes de estas representaciones para textos, veamos visualmente cómo los editores de código fuente del IDE Visual Studio y el editor de código fuente Notepad++ diferencian respecto a su impresora estética:

2.1 Visual Studio


Visual Studio hace una distinción visual entre el tipo String y la palabra clave string. La Figura 3 muestra esta diferencia de la impresora estética para la sintaxis de C# en el editor de código fuente de este IDE:
String y string en editor de código fuente de Visual Studio.
Figura 3. String y string en editor de código fuente de Visual Studio.

2.2 Notepad++


En el editor de código fuente Notepad++ sucede algo similar. Véamoslo en la Figura 4:
String y string en editor de código fuente de Notepad++
Figura 4. String y string en editor de código fuente de Notepad++.

2.3 Otros editores

En la Red hay un sin número de herramientas para pegar código fuente C# y compartirlo públicamente o embeberlo en un sitio Web o blog (como ocurre en xCSw). Por ejemplo GitHub Gist [4] también distingue entre ambas representaciones:
String y string en editor de código fuente de GitHub Gist
Figura 5. String y string en editor de código fuente de GitHub Gist.
[Nota: GitHub Gist cuenta con esta impresora estética que ayuda a distinguir entre las representaciones en cuestión, en este blog prefiero utilizar Pastebin.com [5] por su alto grado de compatibilidad entre navegadores.]

3. Enumeración Diferencias Sobresalientes

A parte de atender a las lecturas del curso Twenty C# Questions Explained para comprender la diferencia entre las representaciones de serie de caracteres String y string, acudo a la pregunta c# - What's the difference between String and string? - Stack Overflow [2] en Stackoverflow.com, la cual se haya bien documentada respecto a la diferenciación que estamos estudiando. A continuación un sumario extraído de estas dos fuentes:
  • string es un alias de la clase System.String.
  • Úsese string para cualquier instancia:

    string blog = "Blog xCSw";
  • Para acceder a los métodos estáticos de la clase String, recurra al uso de String:

    string blog = String.Format("Blog {0}", "xCSw");
  • string es una palabra clave, no puede ser utilizada como un identificador:

    String string = "Blog xCSw"; // Genera el error CS1525
  • String no es una palabra clave, por lo tanto  puede ser utilizada como un identificador:
    string String = "Blog xCSw";
  • Para usar la clase String se debe usar el nombre de espacios System:
    using System;
  • Para poder utilizar string como identificador es necesario utilizar el prefijo @:

    String @string = "Blog xCSw";
  • Tanto String como string son compilados en lenguaje intermedio (IL) como System.String.
  • No existen implicaciones de rendimiento entre una representación y otra.
  • En reflection, se debe usar String, en lugar de string.
Me ha parecido interesante el diagrama expuesto en una de las respuestas halladas en [2], el cual consiste en aclarar o recordar que C# es uno de los lenguajes que utiliza el Framework .NET, por lo tanto puede agregar extensiones o construcciones, como por ejemplo, las palabras claves o los alias:
Uso de .NET Framework por parte de C#
Figura 6. Uso de .NET Framework por parte de C# [2].
[Nota: Sugiero la lectura de [2] para obtener aún más detalles acerca de las diferencias de estas dos representaciones de series de caracteres.]

4. Ejemplo de Uso

Este ejemplo es una adaptación del presentado en la pregunta What is the difference between String y string del curso de MVA Twenty C# Questions Explained.

En las líneas 9 y 10 usamos el operador typeof para obtener en tiempo de ejecución el tipo de dato asociado de String y string, junto con su nombre de espacio, respectivamente. En la línea 16 invocamos el método static Concat, de manera analoga, en la línea 17. Estas dos líneas producen los mismos resultados, sin embargo, como mencionamos en la sección anterior, es recomendable, por convención de código, usar String para referirse a sus métodos, en lugar de string.

Compilación:


  1. csc /target:exe DiferenciaStringYstring.cs

Ejecución assembly:


  1. .\DiferenciaStringYstring.exe

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

> Prueba de ejecución (local):
Diferencia entre String y string
Figura 7. Diferencia entre String y string.

5. Recursos

El recuso multimedial presentando en el curso Twenty C# Questions Explained en Microsoft Virtual Academy:

6. Conclusiones

Hemos resaltado varias de las diferencias fundamentales entre el uso de la clase String y la palabra clave del lenguaje C# string. A pesar de las sutiles diferencias, hay que recordar que ambas representaciones son compiladas a la representación intermedia de lenguaje (IL) System.String. Debemos tener claro estas diferencias (las descritas en la sección 3), por ejemplo, cuando vayamos a usar reflection, dado que en este contexto sólo se puede usar String. O en el caso de las convenciones de código, se recomienda el uso de String para la invocación de métodos estáticos de esta clase. La próxima pregunta que estudiáremos cómo obtener el path (ruta) en una aplicación consola.

7. Glosario

  • Consola
  • Convención de código
  • IDE
  • String
  • string
  • Tipo
  • Visual Studio

8. Literatura & Enlaces

[1]: Twenty C# Questions Explained - http://www.microsoftvirtualacademy.com
[2]: c# - What's the difference between String and string? - Stack Overflow - http://stackoverflow.com/questions/7074/whats-the-difference-between-string-and-string
[3]: String Class (System) - http://msdn.microsoft.com/en-us/library/system.string%28v=vs.110%29.aspx
[4]: Gists - https://gist.github.com/
[5]: Pastebin.com - #1 paste tool since 2002! - http://pastebin.com/
[6]: Twenty C# Questions Explained, 03, What is the difference between String and string? - YouTube - https://www.youtube.com/watch?v=KAIYom46FCUCa


J