Re: вопрос по AutoResetEvent
От: Мизантроп  
Дата: 20.09.09 04:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>вывод


А>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();
}
"Нормальные герои всегда идут в обход!"
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.