← Назад к вопросам
Почему Mutex может работать между процессами?
2.8 Senior🔥 221 комментариев
#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Почему Mutex может работать между процессами?
Mutex (взаимное исключение) может работать между процессами благодаря тому, что в операционной системе есть **глобальный реестр объектов синхронизации** — ОС хранит и управляет mutex как ресурсом ядра, а не только в памяти приложения.
Архитектура Mutex в Windows
В Windows Mutex реализуется как именованный объект ядра:
// Процесс 1: создание именованного Mutex
var mutex = new Mutex(false, "Global\\MyMutex");
try
{
mutex.WaitOne(); // ждём освобождения
Console.WriteLine("Процесс 1: вошли в критическую секцию");
// критическая секция
}
finally
{
mutex.ReleaseMutex();
Console.WriteLine("Процесс 1: вышли");
}
// Процесс 2: получение доступа к же Mutex
var sameEx = new Mutex(false, "Global\\MyMutex");
try
{
sameEx.WaitOne(); // блокируется, ждёт Процесса 1
Console.WriteLine("Процесс 2: вошли в критическую секцию");
}
finally
{
sameEx.ReleaseMutex();
}
Почему это работает? Потому что:
- Именование (
"Global\\MyMutex") позволяет разным процессам найти один и тот же объект ядра - Ядро ОС хранит state mutex в своей памяти, доступной всем процессам
- Процессы не конфликтуют — ОС гарантирует, что только один процесс может держать Mutex
Внутреннее устройство
ОС Ядро
┌─────────────────────────┐
│ Handle Table (ядра) │
│ ┌──────────────────┐ │
│ │ Mutex: MyMutex │ │ <- Глобальный объект
│ │ Owner: Process2 │ │ <- Кто держит
│ │ Queue: [Proc1] │ │ <- Кто ждёт
│ └──────────────────┘ │
└─────────────────────────┘
Процесс 1 Процесс 2
┌──────────┐ ┌──────────┐
│Handle 0x4│──┐ │Handle 0x8│──┐
└──────────┘ │ └──────────┘ │
└────→ Mutex (ядро) ←───┘
Разница между межпроцессными и внутрипроцессными Mutex
// Только для ОДНОГО потока (внутри одного процесса)
var singleProcessMutex = new Mutex(false); // без имени
// ДЛЯ НЕСКОЛЬКИХ процессов
var multiProcessMutex = new Mutex(false, "Global\\SharedMutex"); // с глобальным именем
// Так же работают:
var namedMutex = new Mutex(false, @"Global\My-Mutex-Name");
var localMutex = new Mutex(false, @"Local\ThreadLocal"); // локальная сессия
Семантика владения и очередь ожидания
var stopwatch = Stopwatch.StartNew();
var mutex = new Mutex(false, "Global\\benchmark");
Console.WriteLine($"[{stopwatch.ElapsedMilliseconds}ms] Ожидание Mutex...");
mutex.WaitOne(); // блокируется, если другой процесс держит
Console.WriteLine($"[{stopwatch.ElapsedMilliseconds}ms] Вошли!");
Thread.Sleep(2000); // держим 2 секунды
mutex.ReleaseMutex();
Console.WriteLine($"[{stopwatch.ElapsedMilliseconds}ms] Отпустили");
Если другой процесс уже держит этот Mutex:
[0ms] Ожидание Mutex...
[2000ms] Вошли! <- блокировался 2 секунды
[4000ms] Отпустили
Пример: координация между двумя процессами
// Program1.exe
static void Main()
{
using (var mutex = new Mutex(false, "Global\\DataAccess"))
{
mutex.WaitOne();
// Читаем файл, изменяем БД, etc.
File.WriteAllText("shared.txt", "Data from Process 1");
System.Diagnostics.Debug.WriteLine("Process 1 writing...");
Thread.Sleep(3000);
mutex.ReleaseMutex();
}
}
// Program2.exe (одновременно запущена)
static void Main()
{
using (var mutex = new Mutex(false, "Global\\DataAccess"))
{
mutex.WaitOne(); // БЛОКИРУЕТСЯ здесь, пока Process 1 не отпустит
var data = File.ReadAllText("shared.txt");
Console.WriteLine($"Process 2 reads: {data}"); // Будет "Data from Process 1"
mutex.ReleaseMutex();
}
}
Ограничения и опасности
-
Абандонированный Mutex — если процесс умрёт не отпустив Mutex, он зависнет
try { mutex.WaitOne(); } catch (AbandonedMutexException) { // Предыдущий процесс умер, но mutex гарантировано передан нам } -
Производительность — межпроцессная синхронизация медленнее (переходы в ядро)
-
Переносимость — Mutex работает по-разному в Windows и Linux
Linux и другие ОС
В Linux используются futex (fast userspace mutex) и POSIX named mutexes. Принцип такой же — ядро хранит глобальное состояние.
Альтернативы
- ReaderWriterLockSlim — только для одного процесса
- Semaphore — счётный семафор (может быть именованным)
- Monitor — встроенная синхронизация (только 1 процесс)
- Lock — простейший вариант (только 1 процесс)