Odpowiedzi:
lock
jest słowem kluczowym kompilatora, a nie rzeczywistą klasą lub obiektem. Jest to opakowanie wokół funkcjonalności Monitor
klasy i zostało zaprojektowane tak, aby Monitor
ułatwić pracę z typowym przypadkiem.
Monitor
(I lock
słów kluczowych) są, jak powiedział Darin, ograniczone do AppDomain
. Przede wszystkim dlatego, że odniesienie do adresu pamięci (w postaci instancji obiektu) jest wymagane do zarządzania „blokadą” i utrzymywania tożsamościMonitor
Z Mutex
drugiej strony, jest otoką .Net wokół konstrukcji systemu operacyjnego i może być używany do synchronizacji w całym systemie, używając danych łańcuchowych (zamiast wskaźnika do danych) jako identyfikatora. Dwa muteksy, które odwołują się do dwóch ciągów w dwóch zupełnie różnych adresach pamięci, ale mają te same dane , będą w rzeczywistości wykorzystywać ten sam muteks systemu operacyjnego.
Mutex
Mogą być zarówno lokalne do procesu lub w całym systemie . MSDN :
Muteksy są dwojakiego rodzaju: lokalne muteksy, które są nienazwane, oraz nazwane muteksy systemowe. Lokalny mutex istnieje tylko w Twoim procesie.
Ponadto należy zachować szczególną ostrożność - wyszczególniono również na tej samej stronie - podczas korzystania z ogólnosystemowego muteksu w systemie z usługami terminalowymi.
Jedna z różnic między Mutex
i lock
polega na tym, że Mutex
wykorzystuje konstrukcję na poziomie jądra , więc synchronizacja zawsze będzie wymagać przynajmniej przejścia między przestrzenią użytkownika a przestrzenią jądra.
lock
- to jest naprawdę skrót do Monitor
klasy , z drugiej strony stara się uniknąć alokacji zasobów jądra i przejścia do kodu jądra (a tym samym jest bardziej oszczędny i szybszy - jeśli trzeba znaleźć konstrukcję WinAPI, która przypomina, to by była CriticalSection
).
Inną różnicą jest to, na co wskazują inni: named Mutex
może być używany w różnych procesach.
Jeśli ktoś nie ma specjalnych potrzeb lub nie wymaga synchronizacji między procesami, lepiej jest trzymać się lock
(aka Monitor
) ²
Istnieje kilka innych „drobnych” różnic, na przykład sposób obsługi porzucenia itp.
To samo można powiedzieć o ReaderWriterLock
i ReaderWriterLockSlim
w 3.5, Semaphore
a także o nowościach SemaphoreSlim
w .NET 4.0 itd. Prawdą jest, że te ostatnie xxSlim
klasy nie mogą być używane jako prymitywy do synchronizacji całego systemu, ale nigdy nie miały do tego celu - miały "tylko" znaczenie być szybszym i bardziej przyjaznym dla zasobów.
Używam Mutex, aby sprawdzić, czy mam już kopię aplikacji uruchomioną na tym samym komputerze.
bool firstInstance;
Mutex mutex = new Mutex(false, @"Local\DASHBOARD_MAIN_APPLICATION", out firstInstance);
if (!firstInstance)
{
//another copy of this application running
}
else
{
//run main application loop here.
}
// Refer to the mutex down here so garbage collection doesn't chuck it out.
GC.KeepAlive(mutex);
Wiele już zostało powiedziane, ale aby to uprościć, oto moje podejście.
lock -> Prosty w użyciu, wrapper na monitorze, blokuje wątki w AppDomain.
nienazwany mutex -> podobny do blokady, z tym że zakres blokowania jest czymś więcej i jest w obrębie AppDomain w procesie.
Nazwany mutex -> zakres blokowania to coś więcej niż nienazwany mutex i obejmuje cały proces w systemie operacyjnym.
Więc teraz są dostępne opcje, musisz wybrać ten, który najlepiej pasuje do twojego przypadku.
Mutex jest procesem krzyżowym i będzie klasyczny przykład nie uruchamiania więcej niż jednej instancji aplikacji.
Drugi przykład mówi, że masz plik i nie chcesz, aby inny proces miał dostęp do tego samego pliku, możesz zaimplementować Mutex, ale pamiętaj o jednej rzeczy Mutex jest systemem operacyjnym i nie może być używany między dwoma zdalnymi procesami.
Blokada to najprostszy sposób ochrony sekcji kodu i jest ona zależna od domeny aplikacji. Możesz zastąpić blokadę monitorami, jeśli chcesz bardziej kontrolowaną synchronizację.
Kilka drobniejszych różnic, które nie zostały wymienione w odpowiedziach:
W przypadku korzystania z zamków możesz być pewien, że blokada zostanie zwolniona, gdy w bloku zamka wydarzy się wyjątek.
To dlatego, że zamek wykorzystuje monitory pod maską i jest realizowany w ten sposób:
object __lockObj = x;
bool __lockWasTaken = false;
try
{
System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
// Your code...
}
finally
{
if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}
Tak więc w każdym przypadku blokada zostaje zwolniona i nie trzeba jej ręcznie zwalniać (tak jak w przypadku muteksów).
W przypadku Locks zwykle używasz prywatnego obiektu do blokowania (i powinieneś go używać ).
Dzieje się tak z wielu powodów. (Więcej informacji: zobacz tę odpowiedź i oficjalną dokumentację ).
Tak więc w przypadku zamków nie możesz (przypadkowo uzyskać) dostępu do zamkniętego obiektu z zewnątrz i spowodować pewne uszkodzenia.
Ale w przypadku Mutexa możesz, ponieważ powszechne jest posiadanie Mutexu, który jest oznaczony jako publiczny i używany z dowolnego miejsca.