Здравствуйте, desco, Вы писали:
D>стремный сценарий:
D>1. Поток 1 делает Enqueue
D>2. Поток 2 (из пула), начавщий выполнять метод SenderJob проходит проверку в while и доходит до места А, не войдя в lock.
D>3. Поток 1 последовательно вызывает Pause и Resume. В итоге посредством магических пассов (выделенный код) в пуле появляется еще один поток (3), выполняющий SenderJob.
D>4. Поток 3 успешно проходит метод SenderJob, вытащив из очереди единственный элемент.
D>5. Просыпается поток 2, заходит под lock ... и успешно обламывается на попытке извлечь элемент из уже пустой очереди. Вуаля.
Спасибо! Вчера голову сломал во время поиска подобного
Я так понимаю это вылечится одной дополнительной проверкой:
public void Resume()
{
if (!this.senderPaused) return;
lock(this.queueSync)
{
this.senderPaused = false;
if (this.msgQueue.Count > 0 && !this.senderAlive)
{
this.senderAlive = true;
ThreadPool.QueueUserWorkItem(SenderJob);
}
}
}
U>Для этого можно использовать AutoResetEvent, вызывая WaitOne для усыпления и Set() для пробуждения потока.
А ивентами не сильно дороже это будет? Объект ядра как-никак...
U>Также можешь глянуть http://files.rsdn.ru/12051/TaskPulling.rar класс LabeledThread, там решалась задача принципиально схожая с твоей.
Спасибо, поглядимс.