← Назад к вопросам

Почему 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();
}

Почему это работает? Потому что:

  1. Именование ("Global\\MyMutex") позволяет разным процессам найти один и тот же объект ядра
  2. Ядро ОС хранит state mutex в своей памяти, доступной всем процессам
  3. Процессы не конфликтуют — ОС гарантирует, что только один процесс может держать 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 процесс)
Почему Mutex может работать между процессами? | PrepBro