Если число процессов относительно невелико, вы можете создать для каждого из них имя EventWaitHandle , и порядок создания дескрипторов ожидания будет определять порядок, в котором процессам разрешено печатать.(См. Раздел «Добавлено позже» ниже, в котором описывается состояние гонки в представленном коде и обсуждается исправление.)
Когда процесс запускается, он пытается создать именованное событие с именем Process0
,Если это удается, это продолжается.Если происходит сбой, он пытается создать именованное событие Process1
, затем Process2
и т. Д. В результате вы получаете одно именованное событие для каждого запускаемого процесса.Существует конструктор EventWaitHandle
, который сообщит вам, был ли дескриптор создан новым.Таким образом, код выглядит примерно так:
List<EventWaitHandle> WaitHandles = new List<EventWaitHandle>();
// at program startup, try to create Process0, with an initial value of set
bool createdNew;
EventWaitHandle wh = new EventWaitHandle(true, EventResetMode.ManualReset, "Process0", out createdNew);
WaitHandles.Add(wh);
int procNum = 1;
while (!createdNew)
{
// Create wait handles with increasing process numbers until one is created new
string whName = "Process" + procNum.ToString();
wh = new EventWaitHandle(false, EventResetMode.ManualReset, whName, out createdNew);
WaitHandles.Add(wh);
++procNum;
}
Теперь процесс знает, какой дескриптор ожидания ему необходим - последний в списке WaitHandles
.Поэтому, когда он завершает свою фазу «жевания», он может ждать этого дескриптора:
WaitHandles[WaitHandles.Count - 1].WaitOne();
// print
// Now notify the next wait handle, but only if it exists.
try
{
string whName = "Process" + WaitHandles.Count.ToString();
WaitHandle wh = EventWaitHandle.OpenExisting(whName);
wh.Set();
wh.Dispose();
}
catch (WaitHandleCannotBeOpenedException)
{
// wait handle doesn't exist
}
Возможно, вы захотите обязательно вызвать Dispose
для каждого элемента в списке WaitHandles
до того, какваша программа завершает работу, хотя Windows очистит ваши ссылки, если вы забудете.
Это должно работать, если у вас не слишком много запущенных процессов.Пока работает какой-либо из этих процессов, в системе останутся «Process0» и все другие именованные дескрипторы ожидания до последнего.Таким образом, если «Process0» заканчивает печать до того, как «Process9» даже запускается, не возникнет проблем с печатью задания вне очереди или передачей навсегда в ожидании уведомления.
Этот метод также позволяет написатьприложение, которое может запускаться и получать все маркеры вместе с их сигнальным состоянием.Такое приложение может использоваться для сигнализации следующего процесса в строке, если один из предыдущих процессов завершился аварийно, без сигнализации.
Добавлено позже:
Мне кажется, что здесь возможны условия гонки.Допустим, есть три маркера ожидания («Process0», «Process1» и «Process2»).Process2 заканчивает печать и пытается уведомить Process3, которого не существует.Затем Process3 запускается до выхода из Process2, что означает, что Process3 получит дескриптор ожидания с именем «Process3», который никогда не будет сигнализирован.
Обходным путем было бы, если бы Process0 выделил свой собственный дескриптор ожидания, а также ожидание.дескриптор для Process1 - то есть дескриптор ожидания, который он должен будет уведомить, когда завершит печать.Все остальные процессы делают то же самое.Вместо того, чтобы выделять свой собственный дескриптор ожидания (за исключением Process0, который выделяет свой собственный дескриптор ожидания И следующий), они выделяют дескриптор ожидания для следующего процесса.Такое действие должно устранить состояние гонки.