Страницы

Поиск по вопросам

воскресенье, 9 февраля 2020 г.

Как правильно использовать Monitor.Wait и Pulse?

#c_sharp #многопоточность


Подскажите, как выполняется данный код:

lock (locker) {
    while (x == 0) {
        if (y > 0) {
            Monitor.Pulse(locker);
            break;
        }
        Monitor.Wait(locker);
    }

    // что-то еще делаем
}


Задача - синхронизация потоков.

Допустим есть очередь, в которую один поток пишет, другой из нее читает. Вот пока
эта очередь пуста, поток "читатель" должен ждать пока не появятся данные.

Я хочу понять для себя, что происходит при вызове Monitor.Wait и  Monitor.Pulse.
Т.е. когда очередь пуста, мы вызываем Monitor.Wait, поток переходит в режим ожидания,
пока ресурс не освободиться (пока не будет данных для чтения), т.е. пока поток "писатель"
не запишет данные и не предупредит следующий поток что ресурс скоро освободится командой
Monitor.Pulse.

Вопрос в следующем, когда поток выходит из состояния - Monitor.Wait, т.е. в цикле
while (x == 0) x - изменится, будет ли еще раз проверяться условие if (y > 0) либо
же будет исполняться следующий после цикла код?
    


Ответы

Ответ 1



Когда вы вызовите Wait, то ваш поток освободит блокирующий объект locker и заблокирует текущий поток. Цикл не завершится. Функция Wait в потоке1 завершится только тогда, кода другой поток(поток2) вызовет функцию Pulse(или PulseAll) для этого объекта и освободит блокирующий объект. Пока поток2 не освободит объект блокировки, функция Wait в потоке1 не завершится. Стоит отметить, что функции Wait, Pulse, PulseAll не могут быть вызваны, если текущий поток не является владельцем блокировки, поэтому обертка их в lock(locker) обязательна. В противном случае, при вызове этих методов возникнет исключение SynchronizationLockException. Ниже поясняющий пример работы функций public static void Main() { object locker = new object(); int x = 0; int y = 0; Task.Run(() => { Thread.Sleep(2000); lock (locker) { Console.WriteLine("Sending a signal..."); Monitor.Pulse(locker); Console.WriteLine("The signal was sent"); x = 1; Thread.Sleep(5000); Console.WriteLine("Sleep in lock finished"); } }); lock (locker) { while (x == 0) { if (y > 0) { Monitor.Pulse(locker); break; } Console.WriteLine("Wait..."); Monitor.Wait(locker); Console.WriteLine("Wait finished"); } Console.WriteLine("While finished"); } } Вывод программы будет следующий: Wait... Sending a signal... The signal was sent Sleep in lock finished Wait finished While finished Ответ на вопрос: Если Wait завершится, условие цикла при x !=0 будет false, соответственно цикл завершится и будет выполнятся код после цикла. Повторной проверки y>0 внутри цикла в этом случае невозможна!

Комментариев нет:

Отправить комментарий