Преимущества Pulse
и Wait
в том, что они могут использоваться в качестве строительных блоков для всех других механизмов синхронизации, включая мьютексы, события, барьеры и т. Д. Есть вещи, которые можно сделать с помощью Pulse
и * 1004.* это невозможно сделать с помощью любого другого механизма синхронизации в BCL.
Все интересное происходит внутри метода Wait
.Wait
выйдет из критической секции и переведет поток в состояние WaitSleepJoin
, поместив его в очередь ожидания.После вызова Pulse
следующий поток в очереди ожидания перемещается в очередь готовности.Как только поток переключается в состояние Running
, он снова входит в критическую секцию.Это важно повторить по-другому.Wait
откроет замок и снова его захватит атомным способом .Ни один другой механизм синхронизации не имеет этой функции.
Лучший способ представить это - попытаться повторить поведение с другой стратегией, а затем посмотреть, что может пойти не так.Давайте попробуем этот эксрайз с ManualResetEvent
, поскольку методы Set
и WaitOne
кажутся такими, как будто они могут быть аналогичными.Наша первая попытка может выглядеть следующим образом.
void FirstThread()
{
lock (mre)
{
// Do stuff.
mre.Set();
// Do stuff.
}
}
void SecondThread()
{
lock (mre)
{
// Do stuff.
while (!CheckSomeCondition())
{
mre.WaitOne();
}
// Do stuff.
}
}
Должно быть легко увидеть, что код может зайти в тупик.Так что же произойдет, если мы попробуем это наивное исправление?
void FirstThread()
{
lock (mre)
{
// Do stuff.
mre.Set();
// Do stuff.
}
}
void SecondThread()
{
lock (mre)
{
// Do stuff.
}
while (!CheckSomeCondition())
{
mre.WaitOne();
}
lock (mre)
{
// Do stuff.
}
}
Можете ли вы увидеть, что здесь может пойти не так?Поскольку мы не вводили блокировку заново после проверки условия ожидания, другой поток мог войти и сделать условие недействительным.Другими словами, другой поток может сделать что-то, что заставит CheckSomeCondition
снова начать возвращать false
до того, как будет восстановлена следующая блокировка.Это определенно может вызвать много странных проблем, если ваш второй блок кода требует, чтобы условие было true
.