Пишу программу. Есть Queue _readedBlocks. С ней работают три функции:
DequeueReaded
public static void EnqueueReaded(Block block)
{
lock (_readedBlocks)
{
_readedBlocks.Enqueue(block);
Monitor.Pulse(_readedBlocks);
}
}
public static Block DequeueReaded()
{
lock (_readedBlocks)
{
if (!_readedBlocks.Any())
{
if (endOfRead)
return null;
Monitor.Wait(_readedBlocks);
}
return _readedBlocks.Dequeue();
}
}
Больше нигде в коде _readedBlocks никак не используется. У меня один поток заполняет _readedBlocks и два потока его опустошают. В какой то момент у меня вылетает исключение "Очередь пуста". Что я делаю не так? По сути же если очередь пуста, поток становится в ожидание. Как только в очередь добавляется элемент, первый из ждущих получает пульс и работает с его добычей, в то время, как второй должен сидеть и ждать, пока заполняющий поток не подтянет еще элементов. Что не тка в этой логике?
Кейс:
Для наглядности я модифицировал твой пример:
lock (_readedBlocks)
{
Console.WriteLine($"Enter: {Thread.CurrentThread.ManagedThreadId}");
if (!_readedBlocks.Any())
{
if (endOfRead)
return null;
Console.WriteLine($"Wait: {Thread.CurrentThread.ManagedThreadId}");
Monitor.Wait(_readedBlocks);
Console.WriteLine($"Release: {Thread.CurrentThread.ManagedThreadId}");
}
Console.WriteLine($"Dequeue: {Thread.CurrentThread.ManagedThreadId}");
return _readedBlocks.Dequeue();
}
Перед exception получился вот такой output:
Wait: 4
Pulse: 3
Enter: 5
Dequeue: 5
Release: 4
Dequeue: 4
Имхо, в твоем случае, самой лайтовой правкой будет обернуть Wait как-нибудь вот так:
do {
Monitor.Wait(_readedBlocks);
} while (!_readedBlocks.Any());
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости