Просто используйте BlockingCollection
вместо Queue
. Это потокобезопасно и будет блокироваться на Take
, пока какой-нибудь рабочий не добавит элемент:
// Use default constructor to make BlockingCollection FIFO
private BlockingCollection<byte[]> messageQueue = new BlockingCollection<byte[]>();
//thread 2 method
private void ProcessIncomingMessages()
{
while (true)
{
//will block until thread1 Adds a message
byte[] message = messageQueue.Take();
//processing messages
}
}
public void SubmitMessageForProcessing(byte[] message)
{
messageQueue.Add(message); //enqueue message
}
EDIT2: я забыл упомянуть, что при использовании конструктора по умолчанию BlockingCollection
будет FIFO. На самом деле он будет использовать ConcurrentQueue
в качестве контейнера предметов.
Если вы хотите, чтобы BlockingCollection
вел себя как коллекция LIFO, вам нужно было бы передать IProducerConsumerCollection
, который является LIFO, в конструктор. Обычный класс для этого будет ConcurrentStack
РЕДАКТИРОВАТЬ: Некоторое объяснение того, как ваш Queue
не является потокобезопасным, и это может привести к проблемам с вашим текущим кодом.
Из документации Microsoft по Queue
:
Очередь может одновременно поддерживать несколько читателей, если коллекция не изменена.
Это означает, что вы не можете читать и писать из нескольких потоков одновременно.
Посмотрите на следующий пример, который также относится к другим ответам, которые предлагают просто переместить messageReset.WaitOne()
в ваш блок while(true)
.
SubmitMessageForProcessing
вызывается и сигнализирует messageReset.Set()
- Поток 2 становится активным и пытается прочитать данные.
- Пока поток 2 читает данные,
SubmitMessageForProcessing
вызывается второй раз.
- Теперь вы пишете и читаете одновременно, что приводит к неожиданному поведению (как правило, к исключениям)