调用 BlockingCollection<T> 上的 Dispose 方法

13
我在C# in a Nutshell书籍的示例生产者消费者队列中复用了BlockingCollection(http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT),但有同事问道: “为什么在集合的Dispose中不调用BlockingCollection的Dispose呢?”
我找不到答案,唯一能想到的原因是队列剩余的工作负载将不被处理。然而,当我处置队列时,为什么它不会停止处理呢?
根据What does BlockingCollection.Dispose actually do?,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.
  }
}

2
或许相关:https://dev59.com/lHA75IYBdhLWcg3wo6rx - ken2k
我在处理阻塞集合(例如释放最后一次Take)时遇到了问题,直到我开始使用CancellationToken,参见https://dev59.com/Z2025IYBdhLWcg3w25yy#5759866。 - Aviko
1个回答

17

这是因为那将是一个错误。在所有消费者线程退出之前,集合不能被处理。如果没有互锁,那些线程会失败并引发异常。该类无法意识到可能从集合中提取某些内容的消费者线程,因此它无法合理地知道何时可以安全地处理。它所能做的就是防止生产者添加更多对象,这是合理的。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接