12

アルバハリの簡単な本(http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT)のC#のプロデューサーコンシューマキューの例を再利用しました。同僚は次のように述べています。コレクションの破棄のBlockingCollectionについて?」

答えが見つかりませんでした。考えられる唯一の理由は、キューの残りのワークロードの実行が処理されないことです。しかし、キューを破棄するときに、処理を停止しないのはなぜですか?

「なぜBlockingCollectionを破棄すべきではないのですか?」「BlockingCollectionを破棄しないと害はありますか?」という2番目の質問もあります。多くのプロデューサーコンシューマーキューを生成/破棄していると、問題が発生すると思います(私が望んでいるのではなく、知るためだけに)。 BlockingCollection.Disposeは実際に何をしますか?BlockingCollectionには(明らかに)2つの待機ハンドルが含まれているため、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

それはバグになるからです。すべてのコンシューマースレッドが終了するまで、コレクションを破棄することはできません。それが連動していない場合、それらのスレッドは例外を除いて爆撃します。クラスは、コレクションからどのコンシューマスレッドがプルしている可能性があるかをまったく認識していないため、いつ安全に破棄できるかを合理的に知ることはできません。それができるのは、プロデューサーによってこれ以上オブジェクトが追加されないようにすることだけです。これは合理的です。

これはスレッドの一般的な問題です。安全に破棄するには、スレッドがいつ完了するかを知る必要があります。そもそもスレッドを使用するという点を損なうことがよくありますが、スレッドが終了するまで待ちたくありません。これはThreadクラス自体で最もよく見られ、5つのネイティブオペレーティングシステムハンドルを消費しますが、Dispose()メソッドはありません。それらはファイナライザーによってリリースされる必要があります。こっちも一緒。

于 2012-02-24T12:18:20.970 に答える