Я бы предложил, чтобы каждый раз, когда кто-то рассматривал возможность использования Monitor.Wait()
, он должен писать код, чтобы он работал правильно, если бы Wait
иногда самопроизвольно действовал так, как будто получил импульс.Как правило, это означает, что следует использовать шаблон:
lock(monitorObj)
{
while(notYetReady)
Monitor.Wait(monitorObj);
}
Для вашего сценария я бы предложил сделать что-то вроде:
lock(monitorObj)
{
turn = [[identifier for this "thread"]];
Monitor.PulseAll(monitorObj);
while(turn != [[identifier for this "thread"]])
Monitor.Wait(monitorObj);
}
Невозможно изменить turn
между проверкой того, наступает ли очередь текущего потока и Monitor.Wait
.Таким образом, если Wait
не пропущен, PulseAll
гарантированно пробудит его.Обратите внимание, что код работал бы просто отлично, если бы Wait
спонтанно действовал так, как если бы он получил импульс - он просто вращался, наблюдал, что turn
не был установлен для текущего потока, и возвращался к ожиданию.