2010-02-02 12 views
12

Jak utworzyć Mutex system/multiprocess do koordynowania wielu procesów przy użyciu tego samego niezarządzanego zasobu.Jak utworzyć system Mutex w C#

Tło: Napisałem procedurę, która wykorzystuje drukarkę plików, która może być używana tylko przez jeden proces na raz. Gdybym chciał go użyć w wielu programach uruchomionych na komputerze, potrzebowałbym sposobu na zsynchronizowanie tego w całym systemie.

+0

Oto zawinięte klasy, który obsługuje między blokowanie procesu i opuszczonych warunki MUTEX https://github.com/blinemedical/Inter-process-mutex – devshorts

Odpowiedz

26

Można użyć klasy System.Threading.Mutex, która ma metodę OpenExisting do otwierania nazwanego systemu mutex.

To nie jest odpowiedź na pytanie:

Jak mogę utworzyć Mutex System/wieloprocesowej

Aby utworzyć mutex całego systemu, należy zadzwonić pod System.Threading.Mutex konstruktor, który przyjmuje ciąg jako argument. Jest to również znane jako "nazwany" muteks. Aby sprawdzić, czy istnieje, nie wydaje się znaleźć sposób więcej wdzięku niż próbować haczyk:

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

Teraz, aby być dobrym programistą, trzeba, po zakończeniu programu, należy zwolnić ten mutex

_mutey.ReleaseMutex(); 

lub można go zostawić, w takim przypadku zostanie on nazwany "porzucony", gdy wątek zostanie zamknięty, i pozwoli na utworzenie innego procesu.

[EDIT]

marginesie do ostatniego zdania opisującego mutex, który jest opuszczony, gdy inny wątek nabywa mutex, wyjątek System.Threading.AbandonedMutexException zostanie rzucony mówiąc mu, że został znaleziony w opuszczonym stanie.

[EDIT TWO]

Nie jestem pewien, dlaczego odpowiedział na pytanie w ten sposób rok temu; istnieje (i było) przeciążenie konstruktora, które jest o wiele lepsze w sprawdzaniu istniejącego muteksu. W rzeczywistości kod, który dałem, zdaje się mieć warunek wyścigowy! (I wstydźcie się wszyscy, że mnie nie poprawiliście!) :-P)

Oto stan wyścigu: Wyobraźcie sobie dwa procesy, obaj próbują otworzyć istniejący muteks w tym samym czasie, a obaj dostaną się do sekcji catch kodu . Następnie jeden z procesów tworzy muteks i żyje długo i szczęśliwie. Drugi proces próbuje jednak utworzyć muteks, ale tym razem jest już stworzony! To sprawdzenie/utworzenie muteksu musi być atomowe.

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

Więc ...

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

myślę Sztuką jest to, że wydaje się, że masz możliwość, że nie mamy (wygląda jak wada projektu do mnie). Czasami nie można stwierdzić, czy jesteś właścicielem mutex jeśli wyślesz true dla requestInitialOwnership. Jeśli zdasz true i wydaje się, że rozmowa utworzony mutex, to oczywiście należy do Ciebie (potwierdzone dokumentacją). Jeśli zdasz true i rozmowa nie stworzył mutex, wszystko co wiem jest to, że mutex został już utworzony, nie wiem, czy jakiś inny proces lub wątek, który może tworzony mutex posiada obecnie mutex. Musisz więc upewnić się, że masz WaitOne. Ale jak często robisz to Release? Jeśli jakiś inny proces własnością mutex kiedy masz go, to tylko twoja wyraźne wezwanie do WaitOne musi być Release d. Jeśli wywołanie konstruktora spowodowało Ci właścicielem mutex, a nazywa WaitOne wyraźnie, trzeba dwa Release s.

włożę te słowa na kod:

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

Ponieważ nie widzę sposobu, aby sprawdzić, czy jesteś właścicielem tego mutex, będę zalecamy przejść false do konstruktora, tak aby wiesz, że nie jesteś właścicielem muteksu i wiesz, ile razy dzwonisz pod numer Release.

+0

+1 Świetna odpowiedź. Ten fragment kodu jest bardzo przydatny. – LeopardSkinPillBoxHat

+1

.NET Framework 4.5 dodał metodę ['TryOpenExisting'] (http://msdn.microsoft.com/en-us/library/hh194641.aspx), która nie generuje wyjątku, jeśli muteks jeszcze nie istnieje. –

+0

@ 280Z28 Dzięki za przypomnienie. .NET fx 3.5 ma podobną możliwość (chociaż twierdzę, że ma wadę projektową), o której nie wspomniałem w mojej oryginalnej odpowiedzi, a którą zilustrowałem powyżej w EDIT TWO. –

0

nie widząc swój kod jest trudny do zwrócenia szczególnej doradzić ale istnieje klasa mutex wC#

MSDN

3

Można użyć klasy System.Threading.Mutex, która ma metodę OpenExisting aby otworzyć nazwany mutex systemu .

+0

Dzięki, nie zdawali sobie sprawy, że metoda była co chciałem. –

0

nie miałem powodzenia przy użyciu mutex systemu opisanego powyżej używając Mono pod Linuksem. Prawdopodobnie robię coś prostego, ale poniższe działa dobrze i czyści się ładnie, jeśli proces wychodzi nieoczekiwanie (kill -9). Byłoby zainteresowane usłyszeć komentarze lub krytykę.

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; 

    } 
}