12

我在 Albahari 的 Nutshell 书籍 ( http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT ) 中重用了 C# 中的示例生产者消费者队列,一位同事评论道:“为什么不调用 Dispose在集合的 Dispose 中的 BlockingCollection 上?”

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

除了“为什么不应该处理 BlockingCollection?” 我还有第二个问题“如果你不处理 BlockingCollection 会有害吗?”。我想当您生成/处理大量生产者消费者队列时,它会产生问题(不是我想要的,只是为了知道)。 根据BlockingCollection.Dispose 实际上做什么?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.
  }
}
4

1 回答 1

16

Because that would be a bug. The collection cannot be disposed until all the consumer threads have exited. If that's not interlocked then those threads would bomb with an exception. The class does not in any way have awareness of what consumer threads might be pulling from the collection so it cannot reasonably know when it is safe to dispose. All it can do is prevent any more objects from being added by the producer, that's reasonable.

This is a common problem with threads, safely disposing requires knowing when the thread is complete. Which often defeats the point of using threads in the first place, you don't want to wait until a thread ends. This is most visible in the Thread class itself, it consumes five native operating system handles but doesn't have a Dispose() method. They need to be released by the finalizer. Same here.

于 2012-02-24T12:18:20.970 回答