Синхронизация 2 процессов с использованием объектов межпроцессной синхронизации - Mutex или AutoResetEvent

Рассмотрим следующий сценарий: я запускаю свое приложение, которое во время его выполнения должно запустить другой процесс, и только после того, как второй процесс завершит внутреннюю специфическую инициализацию, мой первый процесс продолжится. Например:

...
// Process1 code does various initializations here
Process.Start("Process2.exe");
// Wait until Process2 finishes its initialization and only then continue (Process2 doesn't exit)
...

Я вижу несколько вариантов:

  • Mutex - Mutex автоматически приходит на ум при рассмотрении межпроцессного общения, однако я не вижу способа заставить Process1 ждать мьютекса, который он сам сгенерировал. Я могу заставить Process2 создать мьютекс и ждать Process1 до создания Mutex (используя функцию опроса и Mutex.OpenExisting)
  • AutoResetEvent. Это было бы прекрасно для этой задачи, однако, похоже, что в .NET они не могут использоваться для межпроцессного общения.
  • CreateEvent. Я могу использовать P/Invoke и использовать функцию Win32 CreateEvent. Теоретически это могло бы предоставить мне все, что мне нужно. Я бы предпочел не использовать собственные функции, если это возможно.
  • Использовать внешний файл. Самый простой способ - просто использовать внешний объект OS (файл, реестр и т.д.). Однако это кажется довольно взломанным.

Я был бы рад услышать ваше мнение по этому делу.

Спасибо!

Ответ 1

Я как раз собирался отредактировать этот ответ, но это не кажется правильным. Поэтому я отправлю свой собственный...

В соответствии с страницами Threads для С#, которая содержит множество учебников по синхронизации, AutoResetEvent не может использоваться для межпроцессной синхронизации.


Однако для межпроцессной синхронизации можно использовать названный EventWaitHandle. На приведенной выше странице посетите Создание раздела ProcessWaitHandle.

Способ, которым вы устанавливаете это, прямолинейный:

  • Создайте EventWaitHandle в процессе 1 перед запуском процесса 2.
  • После запуска процесса 2 вызовите EventWaitHandle.WaitOne, чтобы заблокировать текущий поток.
  • Наконец, создайте EventWaitHandle в процессе 2 и вызовите EventWaitHandle.Set, чтобы освободить ожидающий поток.

Процесс 1

EventWaitHandle handle = new EventWaitHandle(
    false,                                /* Create handle in unsignaled state */
    EventResetMode.ManualReset,           /* Ignored.  This instance doesn't reset. */
    InterprocessProtocol.EventHandleName  /* String defined in a shared assembly. */
);

ProcessStartInfo startInfo = new ProcessStartInfo("Process2.exe");
using (Process proc = Process.Start(startInfo))
{
    //Wait for process 2 to initialize.
    handle.WaitOne();

    //TODO
}

Процесс 2

//Do some lengthy initialization work...

EventWaitHandle handle = new EventWaitHandle(
    false,                           /* Parameter ignored since handle already exists.*/
    EventResetMode.ManualReset,          /* Explained below. */
    InterprocessProtocol.EventHandleName /* String defined in a shared assembly. */
);
handle.Set(); //Release the thread waiting on the handle.

Теперь, в отношении EventResetMode. Выбор EventResetMode.AutoReset или EventResetMode.ManualReset зависит от вашего приложения.

В моем случае мне понадобилось руководство reset, потому что у меня есть много процессов, связанных с одним и тем же процессом. Итак, как только этот же процесс будет инициализирован, все остальные процессы должны иметь возможность выполнять работу. Таким образом, ручка должна оставаться в сигнальном состоянии (no reset).

Для вас автоматический reset может быть полезен, если вам нужно выполнить инициализацию для каждого процесса 1, запускающего процесс 2.


Боковое примечание: InterprocessProtocol.EventHandleName - это просто константа, обернутая внутри DLL, которая обрабатывает как процесс 1, так и ссылку на процесс 2. Вам не нужно это делать, но это защищает вас от неправильного ввода имени и возникновения тупика.

Ответ 2

я бы рассмотрел ** AutoResetEvent **. они могут использоваться для межпроцессного общения, и они релятивист быстро. см. следующую ссылку: Темы для С#

прочитайте раздел "Создание межсетевого события EventWaitHandle"...