Consumer/Producer 与 AutoResetEvent
Consumer/Producer with AutoResetEvent
我在 C# 中为使用 AutoResetEvent 的消费者和生产者编写了以下代码,但它们在有多个生产者和一个消费者的情况下不起作用。问题是消费者无法消费队列中的所有项目。当我调试时,我注意到消费者只能删除一项然后它 returns false 并且不能再删除。好像问题出在 AutoResetEvent 上,但我想不出问题所在。
private AutoResetEvent newItemSignal = new AutoResetEvent(false);
private Queue<Task> iQueue = new Queue<Task>();
public void Enqueue(Task task)
{
lock (((ICollection)iQueue).SyncRoot)
{
iQueue.Enqueue(task);
newItemSignal.Set();
}
}
public bool Dequeue(out Task task, int timeout)
{
if (newItemSignal.WaitOne(timeout, false))
{
lock (((ICollection)iQueue).SyncRoot)
{
task = iQueue.Dequeue();
}
return true;
}
task = default(Task);
return false;
}
通过使用 AutoResetEvent,您将程序设计为一次只有一个消费者可以消费一个项目。
如果你想坚持类似的设计,你可以改用ManualResetEvent,重置当任何一个消费者线程发现没有物品被消费时的事件,并且设置当生产者线程知道至少有一个项目被消费时的事件。
您可以使用 Monitor class here
找到替代设计
如果您使用的是 .NET 4.0 或更高版本,您也可以使用 Blocking collection
像这样使用 AutoResetEvent 的问题是您可能会调用 Set() 两次或更多次,但 WaitOne() 只会调用一次。在已经发出信号的 ARE 上调用 Set() 总是会失败,项目会卡在队列中。一个标准的线程竞争错误。看起来您可以通过清空消费者中的整个队列来修复它。不是真正的修复,生产者仍然可以领先于消费者,你只是将几率降低到每月一次的不可调试阶段。
ARE不能这样,不能算。使用 Semaphore/Slim 代替,它以线程安全的方式计算。或者使用一个ConcurrentQueue,添加一个class来解决这种编程问题。
我在 C# 中为使用 AutoResetEvent 的消费者和生产者编写了以下代码,但它们在有多个生产者和一个消费者的情况下不起作用。问题是消费者无法消费队列中的所有项目。当我调试时,我注意到消费者只能删除一项然后它 returns false 并且不能再删除。好像问题出在 AutoResetEvent 上,但我想不出问题所在。
private AutoResetEvent newItemSignal = new AutoResetEvent(false);
private Queue<Task> iQueue = new Queue<Task>();
public void Enqueue(Task task)
{
lock (((ICollection)iQueue).SyncRoot)
{
iQueue.Enqueue(task);
newItemSignal.Set();
}
}
public bool Dequeue(out Task task, int timeout)
{
if (newItemSignal.WaitOne(timeout, false))
{
lock (((ICollection)iQueue).SyncRoot)
{
task = iQueue.Dequeue();
}
return true;
}
task = default(Task);
return false;
}
通过使用 AutoResetEvent,您将程序设计为一次只有一个消费者可以消费一个项目。
如果你想坚持类似的设计,你可以改用ManualResetEvent,重置当任何一个消费者线程发现没有物品被消费时的事件,并且设置当生产者线程知道至少有一个项目被消费时的事件。
您可以使用 Monitor class here
找到替代设计如果您使用的是 .NET 4.0 或更高版本,您也可以使用 Blocking collection
像这样使用 AutoResetEvent 的问题是您可能会调用 Set() 两次或更多次,但 WaitOne() 只会调用一次。在已经发出信号的 ARE 上调用 Set() 总是会失败,项目会卡在队列中。一个标准的线程竞争错误。看起来您可以通过清空消费者中的整个队列来修复它。不是真正的修复,生产者仍然可以领先于消费者,你只是将几率降低到每月一次的不可调试阶段。
ARE不能这样,不能算。使用 Semaphore/Slim 代替,它以线程安全的方式计算。或者使用一个ConcurrentQueue,添加一个class来解决这种编程问题。