2010-02-02 10 views
12

Wie kann ich ein System/Multiprozess Mutex erstellen, um mehrere Prozesse mit der gleichen nicht verwalteten Ressource zu koordinieren.Wie kann ich einen System Mutex in C# erstellen

Hintergrund: Ich habe eine Prozedur geschrieben, die einen Dateidrucker verwendet, der nur von einem Prozess zu einem Zeitpunkt verwendet werden kann. Wenn ich es für mehrere Programme verwenden möchte, die auf dem Computer ausgeführt werden, würde ich eine Möglichkeit benötigen, dies über das System zu synchronisieren.

+0

Hier ist ein eingewickelt Klasse, die zwischen den Prozessverriegelungsgriffe und verlassen Mutex Bedingungen https://github.com/blinemedical/Inter-process-mutex – devshorts

Antwort

26

Sie können die System.Threading.Mutex-Klasse verwenden, die über eine OpenExisting-Methode verfügt, um einen benannten Systemmutex zu öffnen.

Das ist nicht die Frage beantwortet:

Wie kann ich ein System/Multi-Prozess-Mutex

Um eine systemweite Mutex zu erstellen, rufen Sie die System.Threading.Mutex erstellen Konstruktor, der eine Zeichenfolge als Argument akzeptiert. Dies wird auch als "benannter" Mutex bezeichnet. Um zu sehen, wenn es vorhanden ist, kann ich nicht eine anmutige Methode zu finden scheine, als Fang versuchen:

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

Nun, um einen guter Programmierer zu sein, müssen Sie, wenn Sie das Programm zu beenden, lassen Sie dieses Mutex

oder Sie können es in diesem Fall verlassen wird verlassen, wenn Ihr Thread beendet wird, und wird es einem anderen Prozess erlauben, es zu erstellen.

[EDIT]

Als Randnotiz auf den Satz zuletzt den Mutex beschreibt, die abgebrochen wird, wenn ein anderer Thread den Mutex erwirbt, wird die Ausnahme System.Threading.AbandonedMutexException ihm erzählte geworfen werden, in dem verlassenen Zustand gefunden.

[EDIT TWO]

Ich bin mir nicht sicher, warum ich vor der Frage, die Art und Weise Jahren beantwortet wird; Es gibt (und war) eine Konstruktorüberladung, die viel besser nach einem vorhandenen Mutex sucht. Tatsächlich scheint der Code, den ich gab, eine Wettlaufbedingung zu haben! (Und Schande über euch alle, dass ihr mich nicht korrigiert! :-))

Hier ist die Race-Bedingung: Stellen Sie sich zwei Prozesse vor, beide versuchen gleichzeitig den vorhandenen Mutex zu öffnen und beide gelangen in den Catch-Bereich des Codes . Dann erzeugt einer der Prozesse den Mutex und lebt glücklich danach. Der andere Prozess versucht jedoch, den Mutex zu erstellen, aber dieses Mal ist er bereits erstellt! Dieses Überprüfen/Erstellen eines Mutex muss atomar sein.

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

So ...

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

Ich denke, der Trick ist, dass es scheint, dass Sie eine Option, die Sie eigentlich gar nicht haben (sieht aus wie ein Design-Fehler für mich). Sie können manchmal nicht feststellen, ob Sie den Mutex besitzen, wenn Sie true für requestInitialOwnership senden. Wenn Sie true übergeben und es scheint, dass Ihr Anruf den Mutex erstellt hat, dann besitzen Sie es offensichtlich (bestätigt durch Dokumentation). Wenn Sie true übergeben und Ihr Aufruf den Mutex nicht erstellt hat, wissen Sie nur, dass der Mutex bereits erstellt wurde. Sie wissen nicht, ob ein anderer Prozess oder Thread, der den Mutex erstellt hat, derzeit den Mutex besitzt. Also, Sie müssen WaitOne um sicherzustellen, dass Sie es haben. Aber dann, wie viele Release s machst du? Wenn ein anderer Prozess den Mutex besitzt, als Sie ihn erhalten haben, dann muss nur Ihr expliziter Aufruf an WaitOneRelease d sein. Wenn Ihr Aufruf an den Konstruktor dazu führte, dass Sie den Mutex besitzen und Sie WaitOne explizit aufgerufen haben, benötigen Sie zwei Release s.

Ich werde diese Worte in Code setzen:

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

Da ich keine Möglichkeit sehen, zu testen, ob Sie gerade den Mutex besitzen, werde ich empfehlen, dass Sie false an den Konstruktor übergeben, so dass Sie wissen, dass Sie den Mutex nicht besitzen, und Sie wissen, wie oft Sie Release anrufen.

+0

+1 Große Antwort. Dieses Code-Snippet ist sehr nützlich. – LeopardSkinPillBoxHat

+1

Das .NET Framework 4.5 hat die Methode ['TryOpenExisting'] (http://msdn.microsoft.com/en-us/library/hh194641.aspx) hinzugefügt, die keine Ausnahme auslöst, wenn der Mutex noch nicht existiert. –

+0

@ 280Z28 Danke für die Erinnerung. Das .NET fx 3.5 hat eine äquivalente Fähigkeit (obwohl ich argumentiere, dass es einen Designfehler hat), die ich in meiner ursprünglichen Antwort nicht erwähnt habe und die ich oben in EDIT TWO illustriert habe. –

0

, ohne den Code zu sehen, ist es schwierig, spezifische Ratschläge zu geben, aber es gibt eine Mutex-Klasse in C#

MSDN

3

Sie die System.Threading.Mutex Klasse verwenden können, die eine OpenExisting Methode ein benanntes System Mutex zu öffnen hat .

+0

Dank, nicht wusste, dass Verfahren war das, was ich wollte. –

0

Ich hatte nicht viel Glück mit dem oben beschriebenen System Mutex mit Mono unter Linux. Ich mache wahrscheinlich nur etwas Einfaches falsch, aber das Folgende funktioniert gut und räumt gut auf, wenn der Prozess unerwartet beendet wird (kill -9). Ich wäre interessiert, Kommentare oder Kritik zu hören.

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; 

    } 
} 
Verwandte Themen