2010-02-02 26 views
12

? Cómo puedo crear un Mutex de sistema/multiproceso para coordinar múltiples procesos usando el mismo recurso no administrado.¿Cómo puedo crear un Mutex del sistema en C#

Antecedentes: He escrito un procedimiento que utiliza una impresora de archivos, que solo se puede utilizar por un proceso a la vez. Si quisiera usarlo en múltiples programas que se ejecutan en la computadora, necesitaría una forma de sincronizar esto en todo el sistema.

+0

Aquí es una clase que se encarga de bloqueo envuelta entre procesos y las condiciones de exclusión mutua abandonados https://github.com/blinemedical/Inter-process-mutex – devshorts

Respuesta

26

Puede usar la clase System.Threading.Mutex, que tiene un método OpenExisting para abrir un mutex del sistema con nombre.

eso no responde a la pregunta:

¿Cómo puedo crear un mutex sistema/multiproceso

Para crear un mutex de todo el sistema, llame a la System.Threading.Mutex constructor que toma una cadena como argumento Esto también se conoce como mutex 'named'. Para ver si existe, me parece que no puede encontrar un método más elegante de tratar de captura:

System.Threading.Mutex _mutey = null; 
try 
{ 
    _mutey = System.Threading.Mutex.OpenExisting("mutex_name"); 
    //we got Mutey and can try to obtain a lock by waitone 
    _mutey.WaitOne(); 
} 
catch 
{ 
    //the specified mutex doesn't exist, we should create it 
    _mutey = new System.Threading.Mutex("mutex_name"); //these names need to match. 
} 

Ahora, para ser un buen programador, es necesario, cuando finaliza el programa, liberar esta exclusión mutua

_mutey.ReleaseMutex(); 

o, puede dejarlo en este caso se llamará 'abandonado' cuando su hilo se cierre, y permitirá que otro proceso lo cree.

[EDIT]

Como nota al margen de la última frase que describe el mutex que se abandona, cuando otro hilo adquiere el mutex, a excepción System.Threading.AbandonedMutexException será lanzada diciéndole que se encontró en el estado de abandono.

[EDICIÓN DE DOS]

No estoy seguro de por qué respondieron a la pregunta hace que las vías años; hay (y hubo) una sobrecarga de constructor que es mucho mejor al comprobar si hay un mutex existente. ¡De hecho, el código que di parece tener una condición de carrera! (¡Y les tengo vergüenza a todos por no corregirme! :-P)

Aquí está la condición de carrera: imagine dos procesos, ambos intentan abrir el mutex existente al mismo tiempo, y ambos llegan a la sección catch del código . Entonces, uno de los procesos crea el mutex y vive feliz para siempre. El otro proceso, sin embargo, intenta crear el mutex, ¡pero esta vez ya está creado! Esta comprobación/creación de un mutex debe ser atómica.

http://msdn.microsoft.com/en-us/library/bwe34f1k(v=vs.90).aspx

Así que ...

var requestInitialOwnership = false; 
bool mutexWasCreated; 
Mutex m = new Mutex(requestInitialOwnership, 
     "MyMutex", out mutexWasCreated); 

Creo que el truco aquí es que parece que usted tiene una opción que en realidad no tiene (se parece a un defecto de diseño para mí). A veces no puede decir si posee el mutex si envía true para requestInitialOwnership. Si pasa true y parece que su llamada creó el mutex, entonces obviamente lo posee (confirmado por la documentación). Si pasa true y su llamada no creó el mutex, todo lo que sabe es que el mutex ya se creó, no sabe si algún otro proceso o subproceso que tal vez creó el mutex posee actualmente el mutex. Por lo tanto, tiene que WaitOne para asegurarse de tenerlo. Pero entonces, ¿cuántos Release s haces? Si algún otro proceso era propiedad del mutex cuando lo obtuvo, entonces solo su llamada explícita al WaitOne debe ser Release d. Si su llamada al constructor le hizo poseer el mutex y llamó al WaitOne explícitamente, necesitará dos Release s.

Voy a poner estas palabras en código:

var requestInitialOwnership = true; /*This appears to be a mistake.*/ 
bool mutexWasCreated; 
Mutex m = new Mutex(requestInitialOwnership, 
     "MyMutex", out mutexWasCreated); 

if (!mutexWasCreated) 
{ 
    bool calledWaitOne = false; 
    if (! iOwnMutex(m)) /*I don't know of a method like this*/ 
    { 
     calledWaitOne = true; 
     m.WaitOne(); 
    } 

    doWorkWhileHoldingMutex(); 

    m.Release(); 
    if (calledWaitOne) 
    { 
     m.Release(); 
    } 
} 

Dado que no veo una manera de probar si usted posee actualmente el mutex, yo le recomiendo encarecidamente que se pasa al constructor false de manera que usted sabe que no posee el mutex y sabe cuántas veces debe llamar al Release.

+0

+1 Gran respuesta. Ese fragmento de código es muy útil. – LeopardSkinPillBoxHat

+1

.NET Framework 4.5 agregó el método ['TryOpenExisting'] (http://msdn.microsoft.com/en-us/library/hh194641.aspx) que no arroja una excepción si el mutex no existe. –

+0

@ 280Z28 Gracias por el recordatorio. El .NET fx 3.5 tiene una capacidad equivalente (aunque sostengo que tiene un defecto de diseño) que no mencioné en mi respuesta original y que ilustré anteriormente en EDITAR DOS. –

0

sin ver su código que es difícil dar consejos específicos, pero hay una clase de exclusión mutua en C#

MSDN

3

Usted puede utilizar la clase System.Threading.Mutex, que tiene un método OpenExisting para abrir un mutex sistema denominado .

+0

Gracias, no se dio cuenta que el método era lo que quería. –

0

No he tenido suerte usando el sistema Mutex descrito anteriormente usando Mono en Linux. Probablemente estoy haciendo algo simple mal, pero el siguiente funciona bien y se limpia muy bien si el proceso se cierra inesperadamente (kill -9). Estaría interesado en escuchar comentarios o críticas.

class SocketMutex{ 
    private Socket _sock; 
    private IPEndPoint _ep; 
    public SocketMutex(){ 
     _ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7177); 
     _sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 
     _sock.ExclusiveAddressUse = true; // most critical if you want this to be a system wide mutex 
    } 

    public bool GetLock(){ 
     try{   
      _sock.Bind(_ep); // 'SocketException: Address already in use' 
     }catch(SocketException se){ 
      Console.Error.WriteLine ("SocketMutex Exception: " se.Message); 
      return false; 
     } 
     return true; 

    } 
} 
Cuestiones relacionadas