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.

jueves, 30 de octubre de 2008

Exclusión mutua

Hay ocasiones en las que puede interesarnos que sólo exista una instancia de una aplicación ejecutándose. Uno de los métodos más habituales es usar la API de Windows para comprobarlo. Podemos conseguirlo utilizando la función FindWindow de la DLL User32 del sistema, como ya vimos hace bastante tiempo en el blog.
Un método más común en .NET es utilizar la clase Process, que también sirve para lanzar aplicaciones externas a la nuestra como procesos, para comprobar si existe ese proceso en ejecución. La forma de hacerlo es bastante simple, basta con obtener los procesos que se están ejecutando con el nombre de la aplicación actual, o lo que es lo mismo:



[csharp]
bool CheckIfExists()
{
Return (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).GetUpperBound(0) > 0);
}
[/csharp]


Sin embargo, no es tampoco el mejor método, ya que en.NET las aplicaciones no se ven separadas como procesos independientes, tal y como ocurría con las aplicaciones tradicionales, sino que se separan en distintos AppDomains, que contienen el entorno adecuado para la ejecución de las mismas. Por esto, dentro de un mismo proceso podríamos tener varios dominios de aplicación y en ese caso el método GetProcessesByName de la clase Process no resolvería el problema.
Mucho más eficiente resulta la clase Mutex (Exclusión Mutua), del espacio de nombres System.Threading. Esta clase permite la sincronización entre procesos, controlando el acceso a un recurso compartido.


El uso de esta clase es muy sencillo, como podremos observar en el siguiente ejemplo:



[csharp]
bool recursoLibre;
// Comprueba si podemos tomar el control del “mutex”
Mutex mutex = new Mutex(false, "MiMutex", out recursoLibre);
if (recursoLibre)
{
// Comienza la ejecución de la aplicación…
}
else
{
// Tratar el problema o salir de la aplicación
}
[/csharp]


Este constructor en cuestión, indica en sus parámetros si la instancia actual tendría la propiedad del mutex si su llamada fue la que lo creó, el nombre del mutex (que será usado para comprobar la concurrencia de varios procesos al mismo) y nos devolverá si está libre o no. Si lo está, podemos proceder a continuar con nuestra aplicación (o con el acceso al recurso, si fuera el caso), y si no, deberemos tratar dicho error, esperando un tiempo a que quede libre, terminando la ejecución, etc.


Dentro de los constructores que tiene Mutex existe uno que permite que le pasemos un objeto del tipo MutexSecurity, que permitirá definir los privilegios de acceso al mutex, ya que dicha clase especifica cómo se auditan los intentos de acceso al mismo. El control se lleva a cabo encapsulando el manejo de las listas de control de acceso discreccional (DACL), que controla el acceso al objeto protegido, y una lista de control de acceso al sistema (SACL) que indicará los intentos de acceso a ser auditados. Dado que no es el ámbito de esta entrada, no profundizaré en este tema de momento, pero avanzo que espero escribir en breve sobre dicho tema, además del control de acceso a los procesos y la auditoría de los mismos por parte de .NET.

2 comentarios:

  1. Supongo que esta comprobación que se hace con mutex asegura que el recurso en cuestión será utilizado por un solo proceso. ¿Qué diferencia existe entonces con la palabra reservada lock de C#? ¿Son similares, podrían utilizarse conjuntamente?

    SaludoX.

    ResponderEliminar
  2. Buenas Lonifasiko.

    Pues la verdad es que, aunque parecidos, son son lo mismo... Pero como quedará mejor explicado con un ejemplo, ahí va esa entrada-respuesta: ¿lock o mutex? He ahí la cuestión ;) .

    ResponderEliminar