Здравствуйте, Пельмешко, Вы писали:
стремный сценарий:
1. Поток 1 делает Enqueue
2. Поток 2 (из пула), начавщий выполнять метод SenderJob проходит проверку в while и доходит до места А, не войдя в lock.
while (this.msgQueue.Count > 0
&& !this.senderPaused)
{
string message;
// A
lock (this.queueSync)
{
message = this.msgQueue.Dequeue();
}
RaiseReceived(message);
Thread.Sleep(this.timeout);
}
3. Поток 1 последовательно вызывает Pause и Resume. В итоге посредством магических пассов (выделенный код) в пуле появляется еще один поток (3), выполняющий SenderJob.
// Возобновление отправок
public void Resume()
{
if (!this.senderPaused) return;
lock (this.queueSync)
{
this.senderPaused = false;
if (this.msgQueue.Count > 0)
{
// все проверки выполняются, попадаем сюда
this.senderAlive = true;
ThreadPool.QueueUserWorkItem(SenderJob);
}
}
}
4. Поток 3 успешно проходит метод SenderJob, вытащив из очереди единственный элемент.
5. Просыпается поток 2, заходит под lock ... и успешно обламывается на попытке извлечь элемент из уже пустой очереди. Вуаля.