Итак, я понял, что вы хотите использовать по существу ConcurrentQueue
, но вы застряли в .NET 3.5 и не можете его использовать (потому что он не существует).
Это восходит к простой операции блокировки. Вы не хотите, чтобы два потока обращались к одному и тому же объекту одновременно.
Перед началом работы : Читать Эта книга по C # Threading Джозефом Альбахари
Он распространяется на потоки .NET, и даже простое его сглаживание поможет вам избежать грубых ошибок потоков.
Есть две вещи, которые вам по сути нужно сделать, поэтому давайте разберемся с этим:
Безопасный доступ к очереди
Вы можете использовать Generic Queue<T> Class
для реализации своей очереди сообщений, однако все операции, которые изменяют этот объект, должны безопасно обрабатываться.
Простейшей формой этого является использование оператора блокировки .
lock(myQueue)
{
myQueue.Enqueue(message);
}
Вы должны заблокировать все операции, поэтому вам нужно указать три .Enqueue(...)
, .Dequeue()
и .Count
, поскольку все они имеют доступ к данным.
Это предотвратит проблемы с многопоточностью при постановке в очередь / снятии очереди с ваших сообщений, и жизнь будет хорошей.
Ожидание сообщения
Чтобы дождаться сообщения, у вас есть несколько способов решить эту проблему. Большинство из них описаны в электронной книге, на которую я ссылаюсь выше.
Самым простым является Thread.Sleep
Петля
while(appIsRunning)
{
Thread.Sleep(100);
lock(myQueue)
{
while(myQueue.Count > 0)
{
Console.WriteLine(myQueue.Dequeue());
}
}
}
Примечание. Это не ЛУЧШИЙ способ сделать это, просто самый простой пример
То, что это делает, просто планирует этот поток для запуска снова, по крайней мере, через 100 мс. (Нет гарантии, что он будет работать через 100 мс, но не раньше того времени). Затем он блокирует очередь, поэтому запись в нее невозможна, он очищает очередь и записывает строки на экран, а затем снова зацикливается.
Если очередь пуста, она просто вернется в спящий режим.
Другое решение использует Pulse / Wait
Monitor.Pulse
и Monitor.Wait
- парадигма управления потоками в стиле пинг-понга.
Вы можете иметь свой цикл в главном потоке Monitor.Wait()
, а когда вы добавляете сообщение в очередь, вы можете Monitor.Pulse()
снять блокировку с ожидающего потока.
Это более семантически релевантно, но, вероятно, менее эффективно, потому что переключение контекста происходит по требованию для каждого сообщения.
Существует около 10 других способов сделать это, большинство из них описаны в этой книге, но это по сути дела.
См. Раздел сигнализации о событиях в книге Иосифа , где приведены примеры всех методов сигнализации.