если я оставлю его включенным достаточно долго, я получу исключение, потому что один из потоков удаления выходит из состояния ожидания, даже когда очередь пуста. Кто-нибудь знает, почему я получаю исключение?
Вопрос странный, потому что, очевидно, вы знаете ответ: ваше первое предложение отвечает на вопрос, заданный вторым предложением. Вы получаете исключение, потому что поток удаления выходит из состояния ожидания, когда очередь пуста.
Чтобы решить эту проблему, вам нужно использовать цикл вместо «если». Правильный код:
while(q.Count == 0) Monitor.Wait(q);
не
if(q.Count == 0) Monitor.Wait(q);
UPDATE:
Комментатор указывает, что, возможно, ваш вопрос был задуман так: «при каких обстоятельствах потребительский поток может получить монитор, когда очередь пуста?»
Что ж, вы в лучшем положении, чтобы ответить на этот вопрос, чем мы, так как именно вы запускаете программу и смотрите на результаты. Но это может произойти следующим образом:
- Потребительская нить 1: ожидание
- Поток клиента 2: готов
- Producer Thread 3: владеет монитором
- В очереди один элемент.
- Резьба 3 импульса.
- Поток 1 переходит в состояние готовности.
- Тема 3 покидает монитор.
- Резьба 2 входит в монитор.
- Поток 2 потребляет элемент в очереди
- Поток 2 покидает монитор.
- Поток 1 входит в монитор.
А теперь поток 1 находится на мониторе с пустой очередью.
Вообще говоря, рассуждая о подобных проблемах, вы должны думать о «Пульсе» как о голубе с прикрепленной к нему запиской. После освобождения он не имеет связи с отправителем, и если он не может найти свой дом, он умирает в пустыне со своим недоставленным сообщением. Все, что вы знаете, когда используете Pulse, это то, что , если какой-либо поток ожидает, тогда один поток перейдет в состояние готовности в будущем; Вы больше ничего не знаете об относительном времени выполнения операций над потоками.