简体   繁体   English

在BlockingCollection <T>上调用Dispose

[英]Calling Dispose on an BlockingCollection<T>

I've reused the example producer consumer queue from the C# in a Nutshell book of Albahari ( http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT ) and a colleague remarked: "Why isn't the Dispose called on the BlockingCollection in the Dispose of the collection?" 我在Albahari的一本Nutshell书中重用了C#中的示例生产者消费者队列( http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT ),一位同事评论说:“为什么不调用Dispose关于收集处理中的BlockingCollection?“

I couldn't find an answer and the only reason I can come up with is that execution of the remaining workload of the queue wouldn't be processed. 我找不到答案,我能想出的唯一理由是不会处理队列剩余工作量的执行。 However, when I'm disposing the queue, why wouldn't it stop processing? 但是,当我处理队列时,为什么不停止处理呢?

Besides the "Why you shouldn't Dispose the BlockingCollection?" 除了“为什么你不应该处理BlockingCollection?” I've got also a second question "Does it harm if you don't dispose a BlockingCollection?". 我还有第二个问题“如果你不处理BlockingCollection,会不会受到伤害?”。 I suppose when you are spawning/disposing a lot of producer consumer queues it gives problems (not that I want that but just for the cause of knowing). 我想当你产生/处理大量的生产者消费者队列时,它会产生问题(不是我想要的,而只是为了知道的原因)。 According to What does BlockingCollection.Dispose actually do? 根据BlockingCollection.Dispose实际做了什么? BlockingCollection contains two wait handles (obviously) so not calling Dispose will give you some problems. BlockingCollection包含两个等待句柄(显然),所以不调用Dispose会给你一些问题。 Thanks ken2k for pointing this out. 谢谢ken2k指出这一点。

The code I'm talking about: 我正在谈论的代码:

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.
  }
}

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. 这在Thread类本身中最为明显,它消耗了五个本机操作系统句柄,但没有Dispose()方法。 They need to be released by the finalizer. 他们需要由终结者释放。 Same here. 同样在这里。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM