我认为有一个竞赛条件ProducerConsumerQueue
从
http://www.albahari.com/threading/part2.aspx#_Signaling_with_Event_Wait_Handles。下面是代码:ProducerConsumerQueue的竞争条件来自线程在C#
using System;
using System.Threading;
using System.Collections.Generic;
class ProducerConsumerQueue : IDisposable
{
EventWaitHandle _wh = new AutoResetEvent (false);
Thread _worker;
readonly object _locker = new object();
Queue<string> _tasks = new Queue<string>();
public ProducerConsumerQueue()
{
_worker = new Thread (Work);
_worker.Start();
}
public void EnqueueTask (string task)
{
lock (_locker) _tasks.Enqueue (task);
_wh.Set();
}
public void Dispose()
{
EnqueueTask (null); // Signal the consumer to exit.
_worker.Join(); // Wait for the consumer's thread to finish.
_wh.Close(); // Release any OS resources.
}
void Work()
{
while (true)
{
string task = null;
lock (_locker)
if (_tasks.Count > 0)
{
task = _tasks.Dequeue();
if (task == null) return;
}
if (task != null)
{
Console.WriteLine ("Performing task: " + task);
Thread.Sleep (1000); // simulate work...
}
else
_wh.WaitOne(); // No more tasks - wait for a signal
}
}
}
考虑以下执行,其中C是消费者线程,P是生产线和T1,T2,T3是执行时间:
T1: C不进入任务执行,因为队列为空
lock (_locker)
if (_tasks.Count > 0)
T2: P调用EnqueueItem(action)
T3: C到达_wh.WaitOne();
和永远等待(假定生产者停止添加新值)
书中的错误?废话!在严重的一面,生产者是你的* EnqueueTask调用。我不明白你的评论't1',你参考消费者的代码的和平,并说生产者。 – Sinatr
“工作”消耗队列,而任何调用“EnqueueTask”的人都会产生项目。只有当null任务入队时,worker循环才会退出,并且通常应该坐在等待Set事件的最后一行。但同意分支数量和推理超过null在消费者循环中看起来相当费力。当然,在生产代码中,我们会使用像ConcurrentQueue这样更可信的机制。 – StuartLC
为什么代码会在'_wh.WaitOne()'处“永远等待”?调用'EnqueueItem(action)'的代码将在某个时刻调用'_wh.Set()'。 –