2010-02-02 23 views
12

Come posso creare un sistema/multiprocesso Mutex per coordinare più processi utilizzando la stessa risorsa non gestita.Come posso creare un System Mutex in C#

Sfondo: Ho scritto una procedura che utilizza una stampante di file, che può essere utilizzata solo da un processo alla volta. Se volessi usarlo su più programmi in esecuzione sul computer, avrei bisogno di un modo per sincronizzarlo attraverso il sistema.

+0

Ecco una classe avvolto che gestisce tra l'bloccaggio processo e le condizioni mutex abbandonati https://github.com/blinemedical/Inter-process-mutex – devshorts

risposta

26

È possibile utilizzare la classe System.Threading.Mutex, che dispone di un metodo OpenExisting per aprire un mutex di sistema denominato.

Ciò non rispondere alla domanda:

Come posso creare un mutex di sistema/multiprocesso

Per creare un mutex a livello di sistema, chiamare lo System.Threading.Mutex costruttore che prende una stringa come argomento. Questo è anche conosciuto come mutex 'named'. Per vedere se esiste, io non riesco a trovare un metodo più aggraziato che cercare cattura:

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. 
} 

Ora, per essere un buon programmatore, è necessario, quando si termina il programma, rilasciare questo mutex

_mutey.ReleaseMutex(); 

oppure, è possibile lasciarlo nel qual caso verrà chiamato 'abbandonato' quando il thread termina e consentirà a un altro processo di crearlo.

[EDIT]

Come nota a margine per l'ultima frase che descrive il mutex che viene abbandonata, quando un altro thread acquisisce il mutex, l'eccezione System.Threading.AbandonedMutexException sarà gettato dicendogli che è stato trovato in stato di abbandono.

[EDIT TWO]

io non sono sicuro perché ho risposto alla domanda che modo anni fa; c'è (ed era) un sovraccarico del costruttore che è molto meglio nel controllare un mutex esistente. In effetti, il codice che ho dato sembra avere una condizione di gara! (E vergogna su tutti voi per non correggermi! :-P)

Ecco le condizioni della gara: Immaginate due processi, entrambi cercano di aprire il mutex esistente allo stesso tempo, ed entrambi arrivano alla sezione catch del codice . Quindi, uno dei processi crea il mutex e vive felici e contenti. L'altro processo, tuttavia, tenta di creare il mutex, ma questa volta è già stato creato! Questo controllo/creazione di un mutex deve essere atomico.

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

Quindi ...

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

penso che il trucco è che sembra che hai una possibilità che in realtà non hanno (sembra un difetto di progettazione per me). A volte non puoi dire se possiedi il mutex se invii true per requestInitialOwnership. Se passi true e sembra che la tua chiamata abbia creato il mutex, ovviamente lo possiedi (confermato dalla documentazione). Se passi true e la tua chiamata non ha creato il mutex, tutto quello che sai è che il mutex era già stato creato, non sai se qualche altro processo o thread che forse ha creato il mutex attualmente possiede il mutex. Quindi, devi WaitOne per assicurarti di averlo. Ma poi, quanti Release s fai? Se qualche altro processo ha posseduto il mutex quando lo hai ottenuto, solo la tua chiamata esplicita a WaitOne deve essere Release d. Se la tua chiamata al costruttore ti ha causato la proprietà del mutex e hai chiamato lo WaitOne in modo esplicito, avrai bisogno di due Release s.

Metterò queste parole in codice:

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(); 
    } 
} 

Dal momento che non vedo un modo per verificare se si possiede il mutex, mi consiglia vivamente di passare false al costruttore in modo che sai che non possiedi il mutex e sai quante volte chiamare Release.

+0

+1 Ottima risposta. Questo snippet di codice è molto utile. – LeopardSkinPillBoxHat

+1

.NET Framework 4.5 ha aggiunto il metodo ['TryOpenExisting'] (http://msdn.microsoft.com/en-us/library/hh194641.aspx) che non genera un'eccezione se il mutex non esiste già. –

+0

@ 280Z28 Grazie per il promemoria. .NET fx 3.5 ha una capacità equivalente (anche se sostengo che ha un difetto di progettazione) che non ho menzionato nella mia risposta originale e che ho illustrato sopra in EDIT TWO. –

0

senza vedere il tuo codice è difficile da dare consigli specifici, ma c'è una classe mutex in C#

MSDN

3

È possibile utilizzare la classe System.Threading.Mutex, che ha un metodo OpenExisting per aprire un mutex sistema denominato .

+0

Grazie, non si rese conto che il metodo era quello che volevo. –

0

Non ho avuto fortuna usando il System Mutex descritto sopra usando Mono sotto Linux. Probabilmente sto semplicemente facendo qualcosa di semplice ma il seguente funziona bene e si risolve bene se il processo si chiude in modo imprevisto (kill -9). Sarei interessato a sentire commenti o criticità.

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; 

    } 
} 
Problemi correlati