Вызов Dispose для BlockingCollection <T> - PullRequest
10 голосов
/ 24 февраля 2012

Я повторно использовал пример очереди потребителя-производителя из C # в книге «В двух словах» Албахари (http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT)), и коллега заметил: «Почему Dispose не вызывается для BlockingCollection в Dispose коллекции? "

Я не смог найти ответ, и единственная причина, по которой я могу придумать, заключается в том, что выполнение оставшейся рабочей нагрузки очереди не будет обработано. Однако, когда я освобождаю очередь,почему бы не остановить обработку?

Помимо «Почему вы не должны утилизировать коллекцию 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.
  }
}

1 Ответ

12 голосов
/ 24 февраля 2012

Потому что это было бы ошибкой.Коллекция не может быть удалена до тех пор, пока не завершатся все потребительские потоки.Если это не заблокировано, то эти потоки будут бомбить с исключением.Класс никоим образом не знает, какие потребительские потоки могут быть извлечены из коллекции, поэтому он не может разумно знать, когда безопасно утилизировать.Все, что он может сделать, - это предотвратить добавление каких-либо объектов производителем, это разумно.

Это распространенная проблема с потоками, для безопасной утилизации необходимо знать, когда поток завершен.Что часто побеждает смысл использования потоков, во-первых, вы не хотите ждать окончания потока.Это наиболее заметно в самом классе Thread, он использует пять собственных дескрипторов операционной системы, но не имеет метода Dispose ().Они должны быть освобождены финализатором.То же самое и здесь.

...