Відповіді:
lock- це ключове слово компілятора, а не власне клас чи об’єкт. Це обгортка навколо функціональності Monitorкласу і покликана Monitorполегшити роботу з загальною справою.
Як сказала Дарін, Monitor(і lockключове слово) обмежено значенням AppDomain. Перш за все тому, що для управління "замком" та збереження ідентичності пам'яті потрібне посилання на адресу пам'яті (у вигляді екземпляра)Monitor
З Mutexіншого боку, це .Net обгортка навколо конструкції операційної системи і може використовуватися для загальносистемної синхронізації, використовуючи рядкові дані (замість вказівника на дані) в якості ідентифікатора. Два мутекси, що посилаються на два рядки у двох абсолютно різних адресах пам'яті, але мають однакові дані , фактично використовуватимуть ту саму мутекс операційної системи.
А Mutexможе бути локальним для процесу або загальносистемним . MSDN :
Мутекси бувають двох типів: локальні мутекси, які не називаються, та названі системні мутекси. Місцевий мютекс існує лише у вашому процесі.
Крім того, слід бути особливо обережним - детально на тій же самій сторінці - при використанні загальносистемного файлу mutex у системі із службами терміналів.
Однією з відмінностей між Mutexі lockє те, що Mutexвикористовується конструкція на рівні ядра , тому для синхронізації завжди буде потрібно щонайменше перехід простору ядра в простір користувача.
lock- це дійсно ярлик до Monitorкласу , з іншого боку намагається уникати розподілу ресурсів ядра та переходу до коду ядра (і тим самим швидше і швидше - якщо треба знайти конструкцію WinAPI, яка б вона нагадувала, це було б CriticalSection).
Інша відмінність полягає в тому, що вказують інші: названий Mutex може використовуватися в різних процесах.
Якщо хтось не має особливих потреб або не потребує синхронізації між процесами, просто краще дотримуватися lock(aka Monitor) ˛
Існує кілька інших "незначних" відмінностей, як, наприклад, поводження із залишенням тощо.
Те саме можна сказати про ReaderWriterLockі ReaderWriterLockSlimв 3.5, Semaphoreі в новому SemaphoreSlimв .NET 4.0 тощо. Це правда, що останні xxSlimкласи не можна використовувати як примітиви для синхронізації для всієї системи, але вони ніколи не були призначені для цього - вони мали на увазі "лише" щоб бути швидшим та зручнішим для використання ресурсів.
Я використовую Mutex, щоб перевірити, чи є у мене вже копія програми, що працює на одній машині.
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);
Багато вже було сказано, але щоб зробити це просто, ось мій погляд.
lock -> Простий у використанні, обгортка на моніторі, блокування через потоки в AppDomain.
неназваний mutex -> подібний до блокування, за винятком області блокування більше, і він знаходиться через AppDomain в процесі.
Область фіксації mutex -> навіть більше, ніж неназвана mutex, і вона поширюється в операційній системі.
Тож зараз варіанти є, вам потрібно вибрати той, який найкраще підходить для вашого випадку.
Mutex - це перехресний процес, і це буде класичний приклад запуску більш ніж одного екземпляра програми.
Другий приклад - це те, що у вас є файл, і ви не хочете, щоб інший процес отримував доступ до одного файлу, ви можете реалізувати Mutex, але пам’ятайте одне, що Mutex - це операційна система, і вона не може використовуватися між двома віддаленими процесами.
Блокування - це найпростіший спосіб захисту розділу вашого коду, і це специфічно для додатка, ви можете замінити блокування на Монітори, якщо ви хочете більш керованої синхронізації.
Ще кілька незначних відмінностей, про які не було сказано у відповідях:
У разі використання замків, ви можете бути впевнені, що блокування буде звільнено, коли у блоці блокування стане виняток.
Це тому, що замок використовує монітори під капотом і реалізується таким чином:
object __lockObj = x;
bool __lockWasTaken = false;
try
{
System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
// Your code...
}
finally
{
if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}
Таким чином, у будь-якому випадку блокування звільняється, і вам не потрібно звільняти його вручну (як це було б зроблено для мютексів).
Для блокування ви зазвичай використовуєте приватний об'єкт для блокування (і його слід використовувати ).
Це робиться з багатьох причин. (Детальніше: див. Цю відповідь та офіційну документацію ).
Таким чином, у випадку блокування ви не можете (випадково отримати) доступ до заблокованого об’єкта ззовні та завдати певної шкоди.
Але у випадку з Mutex ви можете, так як звичайно мати Mutex, який позначений як загальнодоступний і використовується з будь-якого місця.