我在Albahari(http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT)的Nutshell书中重用了C#中的示例生产者消费者队列,一位同事评论道: “为什么Dispose不会在集合的Dispose中调用BlockingCollection?”
我找不到答案,我能想出的唯一理由是不会处理队列剩余工作量的执行。但是,当我处理队列时,为什么不停止处理呢?
除了“为什么你不应该处理BlockingCollection?”我还有第二个问题“如果你不处理BlockingCollection,会不会受到伤害?”。我想当你产生/处理大量生产者消费者队列时,它会产生问题(不是我想要的,而只是为了知道的原因)。
根据{{3}} BlockingCollection包含两个等待句柄(显然),所以不调用Dispose会给你一些问题。谢谢ken2k指出这一点。
我正在谈论的代码:
public class PCQueue : IDisposable
{
BlockingCollection<Action> _taskQ = new BlockingCollection<Action>();
public PCQueue (int workerCount)
{
// Create and start a separate Task for each consumer:
for (int i = 0; i < workerCount; i++)
Task.Factory.StartNew (Consume);
}
public void Dispose() { _taskQ.CompleteAdding(); }
public void EnqueueTask (Action action) { _taskQ.Add (action); }
void Consume()
{
// This sequence that we’re enumerating will block when no elements
// are available and will end when CompleteAdding is called.
foreach (Action action in _taskQ.GetConsumingEnumerable())
action(); // Perform task.
}
}
答案 0 :(得分:12)
因为那将是一个错误。在所有消费者线程退出之前,不能处理该集合。如果那不是互锁的话,那些线程就会以异常轰炸。该类不以任何方式了解消费者线程可能从集合中提取的内容,因此无法合理地知道何时可以安全处置。它所能做的只是阻止生产者添加任何更多的对象,这是合理的。
这是线程的常见问题,安全处理需要知道线程何时完成。这通常会破坏首先使用线程的重点,你不想等到线程结束。这在Thread类本身中最为明显,它消耗了五个本机操作系统句柄,但没有Dispose()方法。他们需要由终结者释放。同样在这里。