C# 在BlockingCollection上调用Dispose<;T>;

C# 在BlockingCollection上调用Dispose<;T>;,c#,dispose,producer-consumer,blockingcollection,C#,Dispose,Producer Consumer,Blockingcollection,我在Albahari()的一本简而言之的书中重用了C#中的示例生产者-消费者队列,一位同事评论道: “为什么不在集合的Dispose中对BlockingCollection调用Dispose?” 我找不到答案,我能想到的唯一原因是队列剩余工作负载的执行不会被处理。但是,当我处理队列时,为什么它不停止处理 除了“为什么你不应该处置BlockingCollection?”之外,我还有第二个问题“如果你不处置BlockingCollection,会有什么伤害吗?”。我想,当您生成/处理大量生产者-消费

我在Albahari()的一本简而言之的书中重用了C#中的示例生产者-消费者队列,一位同事评论道: “为什么不在集合的Dispose中对BlockingCollection调用Dispose?”

我找不到答案,我能想到的唯一原因是队列剩余工作负载的执行不会被处理。但是,当我处理队列时,为什么它不停止处理

除了“为什么你不应该处置BlockingCollection?”之外,我还有第二个问题“如果你不处置BlockingCollection,会有什么伤害吗?”。我想,当您生成/处理大量生产者-消费者队列时,它会带来问题(不是我希望这样,只是出于了解的原因)。 根据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.
  }
}
公共类PCQueue:IDisposable
{
BlockingCollection_taskQ=新BlockingCollection();
公共PCQueue(int workerCount)
{
//为每个使用者创建并启动单独的任务:
对于(int i=0;i
因为那将是一个bug。在所有使用者线程退出之前,无法释放集合。如果这不是互锁的,那么这些线程就会爆炸,出现异常。该类无论如何都不知道使用者线程可能从集合中提取什么,因此无法合理地知道何时可以安全地进行处置。它所能做的就是防止生产者添加更多的对象,这是合理的


这是线程的常见问题,安全处理需要知道线程何时完成。这通常会在一开始就破坏使用线程的意义,您不希望等待线程结束。这在Thread类本身中最为明显,它使用五个本机操作系统句柄,但没有Dispose()方法。它们需要由终结器发布。这里也一样。

可能相关:在我开始使用CancellationToken之前,我遇到了处理阻塞收集的问题(例如,上次释放Take),请参阅