Nota del autor

Si la entrada que estás leyendo carece de imágenes, no se ve el vídeo que teóricamente lleva incrustado o el código fuente mostrado aparece sin formato, podéis conocer los motivos aquí. Poco a poco iré restableciendo la normalidad en el blog.
Este blog es un archivo de los artículos situados previamente en Lobosoft.es y ha dejado de ser actualizado. Las nuevas entradas pueden encontrarse en www.lobosoft.es. Un saludo,
Lobosoft.

viernes, 31 de octubre de 2008

Me alegra que me haga esa pregunta

En la entrada de ayer introducía el uso de la clase Mutex para evitar el acceso concurrente a un determinado recurso (en ese caso concreto, a la ejecución simultánea dos o más veces de una misma aplicación). Lonifasiko pregunta, muy acertadamente, qué diferencia existe entre el uso de la palabra reservada lock y el propio Mutex. Lo cierto es que tanto la exclusión mutua de Mutex como el uso de monitores (lock implementa la clase Monitor) permiten el acceso exclusivo a recursos, pero cada uno tiene sus propias peculiaridades. Empecemos con lock.


En .NET, la palabra clave lock se puede usar para evitar que dos subprocesos accedan a un mismo objeto de forma simultánea. Esto se consigue pasándole a lock un objeto como argumento, seguido del bloque de código que deseamos ejecutar aisladamente en un subproceso (es decir, sin que interfieran otros subprocesos en su ejecución).



[csharp]
object miCandado = new object();
lock (miCandado)
{
// No molestar ;)
}
[/csharp]


El objeto en cuestión debe estar basado en un tipo de referencia y es usado para definir el ámbito del bloqueo, ya que estará dado por el alcance del objeto dentro de nuestra aplicación (si se ciñe a una determinada función o es mayor, en función de si existen referencias al objeto fuera de la misma). Microsoft, en su infinita sabiduría :P, desaconseja utilizar bloqueos en tipos public, o utilizando instancias de objetos que estén fuera del alcance de la aplicación, así como cadenas, ya que pueden producir interbloqueo entre procesos si otro código fuera del control de la aplicación utiliza ese mismo objeto para llevar a cabo un bloqueo. Resumiendo, que lo ideal es usar para el bloqueo objetos privados o protegidos, excepto las cadenas, que ni por esas: el CLR las “interna”, es decir, existe una única instancia de la cadena para toda la aplicación.


Como decía, la palabra reservada lock implementa la clase Monitor, facilitando su uso. Monitor es una clase del espacio de nombres System.Threading que contiene dos métodos, Enter y Exit. Al igual que con lock, en el método Enter debemos pasarle al monitor el objeto a usar para definir el ámbito del bloqueo. Cuando finalicemos el acceso exclusivo al recurso, debemos indicar su liberación mediante el método Exit. Así, nuestro pequeño ejemplo anterior quedaría como sigue:



[csharp]
object miCandado = new object();

Monitor.Enter(miCandado);
try
{
// No molestar ;)
}
finally
{
System.Threading.Monitor.Exit(miCandado);
}
[/csharp]


Todo esto está muy bien, resulta tan sencillo como el uso de Mutex, y de hecho es incluso más rápido y eficiente. ¿Entonces, por qué usar Mutex? Bien, la diferencia (jejeje, me he hecho de rogar, pero aquí está por fin) está en que lock permite la exclusión mutua entre subprocesos hijos de un mismo proceso, pero no entre subprocesos de distintos procesos. Es decir, podemos excluir el acceso a un recurso dentro de la misma aplicación, pero no entre aplicaciones (procesos) distintos. Por esto, ya que lo que ayer deseábamos era evitar la ejecución simultánea de dos aplicaciones (que en ese caso podrían ser la misma o no, basándonos simplemente en que utilizasen el mismo nombre para el mutex creado), me basé en el uso de la clase Mutex.


Si os interesa el tema de la programación concurrente os recomiendo el recurso Threading in C#, de Joseph Albahari (precisamente en la parte 2 profundiza en las diferencias entre lock, Mutex y la tercera parte en discordia, que de momento le dejaremos a él: el uso de semáforos).

2 comentarios:

  1. Clase realmente magistral en lo que a acceso concurrente a recursos en .NET se refiere, ¡sí señor! En serio, como nunca he tenido la "suerte" de tener que controlar el acceso concurrente a recursos bajo .NET ;-), hasta ahora nunca me había planteado qué diferencias habría entre mutex y lock, pero ahora, gracias a estas dos entradas encadenadas, me queda mucho más claro.

    Que sepas que de aquí en adelante, si me toca lidiar con semáforos y demás historias de éstas, eres el candidato nº 1 a resolver mis dudas ;-).

    Gracias por la clarísima explicación crack y saludoX!

    ResponderEliminar
  2. Muy buenas :)

    Me alegro de que te haya sido de utilidad la entradita encadenada, jejeje. La verdad es que no caí en explicar en el momento las diferencias, y como bien señalabas podía ser motivo de confusión. Bueno, queda pendiente la de los semáforos, aunque el enlace que os dejé es genial a este respecto, con sus ejemplitos y todo.

    Gracias a ti, en cualquier caso, por tus comentarios. Viniendo de un amigo personal del señor Ballmer es todo un honor ;)

    Saludos,

    Mith.

    ResponderEliminar