OOP Course
Сьогодні

Підрозділ 15.6

Клас Mutex

15.6. Клас Mutex Mutex від англ. mutual exclusion — взаємне виключення — примітив синхронізації, що схожий на lock , але має ключову відмінність: Mutex може працювати між процесами , а не лише між потоками одно

15.6. Клас Mutex

Mutex (від англ. mutual exclusion — взаємне виключення) — примітив синхронізації, що схожий на lock, але має ключову відмінність: Mutex може працювати між процесами, а не лише між потоками одного процесу. Це робить його незамінним інструментом у ситуаціях, коли потрібно координувати доступ до ресурсу між кількома запущеними програмами.

Крім міжпроцесного режиму, Mutex підтримує і внутрішньопроцесну синхронізацію. Однак він суттєво повільніший за lock: внутрішньопроцесний lock — це операція на рівні CLR без звернень до ядра ОС; Mutex — це об'єкт операційної системи, і кожне захоплення/звільнення вимагає системного виклику. Тому для синхронізації потоків усередині одного процесу зазвичай краще обирати lock. Mutex обирають тоді, коли міжпроцесна синхронізація є вимогою.

API класу Mutex

Метод / конструктор Опис
new Mutex() Локальний (внутрішньопроцесний) mutex, починає у вільному стані
new Mutex(bool initiallyOwned) true — поточний потік одразу стає власником
new Mutex(bool initiallyOwned, string name) Іменований (міжпроцесний) mutex. name — глобальна системна назва
WaitOne() Захоплює mutex. Блокує, якщо зайнятий
WaitOne(int ms) Захоплення з таймаутом. Повертає bool
ReleaseMutex() Звільняє mutex. Лише потік-власник може це зробити
Dispose() Звільняє системний ресурс

Важлива особливість: mutex є реентерабельним (recursive). Якщо потік, що вже тримає mutex, знову викликає WaitOne(), він пройде без блокування. Але він зобов'язаний викликати ReleaseMutex() рівно стільки разів, скільки викликав WaitOne() — інакше mutex залишиться захопленим.

Базовий приклад: захист спільного ресурсу

Спочатку розглянемо Mutex у ролі звичайного внутрішньопроцесного замку — для розуміння API:

Зверніть на паттерн try/finally: ReleaseMutex() розміщується у блоці finally, щоб гарантувати звільнення навіть при виникненні винятку. Якщо mutex не буде звільнений, всі інші потоки заблокуються назавжди.

Іменований Mutex — захист між процесами

Головна сила Mutex — іменований варіант, що є спільним об'єктом ОС. Два процеси, що створюють Mutex з однаковим іменем, отримують посилання на той самий системний об'єкт:

Параметр out createdNew повертає true, якщо цей процес створив mutex (тобто є першим), або false, якщо mutex вже існував (інший процес вже запущений). Префікс Global\\ означає, що mutex видимий для всіх сесій ОС; Local\\ (або без префікса) — лише для поточної сесії. Іменовані mutex-и працюють і на Linux/macOS (.NET емулює їх через файли в тимчасовому каталозі), тож цей патерн «лише один екземпляр програми» кросплатформений — на відміну від іменованих Semaphore і EventWaitHandle, які підтримуються лише у Windows.

Практичний сценарій: клінічна інформаційна система, де лише один запущений екземпляр може здійснювати запис до бази даних. Спроба запустити другий екземпляр завершиться повідомленням, а не пошкодженням даних.

Тайм-аут очікування

Mutex.WaitOne(ms) дозволяє не блокуватись вічно:

AbandonedMutexException

Коли потік завершується, не звільнивши mutex, наступний потік, що чекає на нього у WaitOne(), отримає виняток AbandonedMutexException. Важлива деталь: разом із винятком цей потік вже став власником mutex — тому після обробки винятку він теж мусить викликати ReleaseMutex(). Це захисний механізм: наступний потік-власник отримає сигнал, що попередній «впав» без коректного завершення, і може прийняти рішення щодо стану спільного ресурсу.

Зверніть увагу, як саме потік «падає» в цьому прикладі: він просто завершує метод, не звільнивши mutex. Імітувати падіння через throw без catch тут не можна: необроблений виняток у будь-якому потоці .NET (не лише в головному) завершує весь процес — до AbandonedMutexException справа просто не дійде. Тому тіло робочого потоку завжди варто обгортати в try/catch і журналювати помилки.

Mutex vs lock: підсумок

Характеристика lock Mutex
Область дії Потоки одного процесу Потоки та різні процеси
Продуктивність Дуже висока (без ОС-викликів) Нижча (об'єкт ядра ОС)
Реентерабельність Так (повторний lock тим самим потоком проходить) Так (рекурсивне захоплення)
Таймаут очікування Лише через Monitor.TryEnter(obj, ms) WaitOne(ms)
AbandonedMutexException Ні Так
Типовий сценарій Захист даних усередині програми Singleton-процес, спільний файл

Правило вибору: для синхронізації потоків усередині одного додатку — lock; якщо потрібна координація між кількома запущеними програмами або захист системного ресурсу — Mutex.

Розроблено Tomka Yurii · © 2026 ·