Monitor.Pulse и PulseAll требует, чтобы блокировка, с которой он работает, была заблокирована во время вызова. Это требование кажется ненужным и вредным для производительности. Моей первой идеей было то, что это привело к 2 потерянным переключениям контекста, но это было исправлено с помощью nobugz ниже (спасибо). Я все еще не уверен, включает ли он потенциал для потерянных переключателей контекста, так как другие потоки, которые ожидали на мониторе, уже доступны для планировщика, но если они запланированы, они будут только возможность выполнить несколько инструкций, прежде чем попасть в мьютекс, и снова придется переключать контекст. Это выглядело бы намного проще и быстрее, если бы блокировка была разблокирована до вызова Monitor.Pulse.
Переменные условия Pthread реализуют ту же концепцию, но не имеют описанного выше ограничения: вы можете вызвать pthread_cond_broadcast, даже если вы не владеете мьютексом. Я вижу это как доказательство того, что требование не обосновано.
Редактировать :
Я понимаю, что блокировка необходима для защиты общего ресурса, который обычно изменяется перед Monitor.Pulse. Я пытался сказать, что эта блокировка могла быть разблокирована после доступа к ресурсу, но до Pulse, учитывая, что Monitor будет поддерживать это. Это поможет ограничить блокировку самым коротким временем, в течение которого осуществляется доступ к общему ресурсу. Как таковой:
void f(Item i)
{
lock(somequeue) {
somequeue.add(i);
}
Monitor.Pulse(somequeue); // error
}