Почему Mutex может работать между процессами?

«Почему Mutex может работать между процессами?» — вопрос из категории Многопоточность, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Mutex (взаимное исключение) может синхронизировать потоки из разных процессов, потому что это объект уровня операционной системы, а не среды выполнения (CLR).

Ключевые отличия от lock/Monitor:

  • lock (Monitor): Работает только в пределах одного процесса и домена приложения (AppDomain), используя память кучи CLR.
  • Mutex: Создается в глобальном пространстве имен ядра ОС (например, в Windows). Разные процессы могут открыть хэндл одного и того же именованного объекта ядра.

Как это работает:

  1. При создании именованного Mutex ОС регистрирует его в своем внутреннем пространстве имен (например, Global\MyAppMutex).
  2. Любой процесс, знающий это имя, может открыть хэндл на тот же самый объект ядра.
  3. Операции WaitOne() и ReleaseMutex() взаимодействуют с этим общим объектом ОС, обеспечивая межпроцессную синхронизацию.

Пример использования именованного Mutex для межпроцессной синхронизации:

// Процесс A: Создает или открывает именованный мьютекс и захватывает его.
using (var mutex = new Mutex(initiallyOwned: true, name: "Global\MySingletonAppMutex"))
{
    Console.WriteLine("Процесс A владеет мьютексом. Нажмите Enter для освобождения.");
    Console.ReadLine();
    mutex.ReleaseMutex();
}

// Процесс B: Открывает существующий мьютекс и пытается его захватить.
bool createdNew;
using (var mutex = new Mutex(initiallyOwned: false, name: "Global\MySingletonAppMutex", out createdNew))
{
    Console.WriteLine($"Процесс B: Мьютекс создан заново? {createdNew}");
    // Ожидаем, пока Процесс A освободит мьютекс.
    Console.WriteLine("Процесс B ждет мьютекс...");
    if (mutex.WaitOne(TimeSpan.FromSeconds(10)))
    {
        Console.WriteLine("Процесс B захватил мьютекс.");
        mutex.ReleaseMutex();
    }
}

Важные замечания:

  • Префикс Global\ в Windows делает мьютекс видимым для всех сессий (полезно для служб).
  • Необходимо аккуратно обрабатывать исключения и всегда освобождать мьютекс в finally или с помощью using.
  • Межпроцессные мьютексы медленнее, чем внутрипроцессные блокировки, из-за переключения в режим ядра.