Синхронизация 2 процессов с использованием межпроцессных объектов синхронизации - Mutex или AutoResetEvent - PullRequest
14 голосов
/ 08 ноября 2010

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

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

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

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

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

Спасибо!

Ответы [ 2 ]

15 голосов
/ 18 марта 2015

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

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


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

Способ его настройки прост:

  • Создать 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 зависит от вашего приложения.

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

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


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

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

, прочитайте раздел Создание кросс-процесса EventWaitHandle ...

...