Здравствуйте, Аноним, Вы писали:
А>вывод
А>Waiting..
А>Performing task: Hello
А>Performing task: Say 0
А>Performing task: Say 1
А>Performing task: Say 2
А>Performing task: Say 3
А>Performing task: Say 4
А>Performing task: Goodbye!
А>Waiting..
А>Waiting..
А>Performing task: Goodbye_II!
А>вопрос: почему Waiting.. два раза?
Вы добавили задания 1, 2, или 1, 2, 3, неважно. Взвели эвент. Поток проснулся, сбросив эвент и начав обрабатывать задания. Пока он обрабатывает первое, Вы добавляете в очередь остальные задания, опять взведя эвент. Но поток-обработчик не обращается к событию, пока в очереди остаются задания. Таким обраазом в очереди все задания, эвент взведён. Обработчик выбрал все задания и перешёл к WaitOne, видит, что он взведён, выходит из ожидания, но очередь уже пуста, он обработал все задания на предыдущем шаге, и потому он опять уходит в ожидиние. Ну а потом Вы добавляете последнее задание и NULL, после чего всё завершается.
Избежать этого можно разными путями, один из возможных:
Заменить AutoResetEvent на ManualResetEvent, сбрасывать его потоком-обработчиком внутри секции Lock при пустой очереди. Взводить, соответственно, тоже внутри Lock, как-то так:
public void EnqueueTask(string task)
{
lock (locker)
{
tasks.Enqueue(task);
if (tasks.Count == 1) wh.Set();
}
}
Выборка:
lock (locker)
{
if (tasks.Count > 0)
{
task = tasks.Dequeue();
if (task == null)
return;
}
if (tasks.Count == 0) wh.Reset();
}