Відповіді:
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, який позначений як загальнодоступний і використовується з будь-якого місця.