Читать «C# 4.0: полное руководство» онлайн - страница 632

Герберт Шилдт

Помимо методов TryAdd() и TryTake(), определяемых параллельно с теми, что указываются в интерфейсе IProducerConsumerCollection<T>, в классе BlockingCollection<T> определяется также ряд собственных методов. Ниже представлены методы, которые будут использоваться в приведенных далее примерах.

public void Add(T item)

public T Take()

Когда метод Add() вызывается для неограниченной коллекции, он добавляет элемент item в коллекцию и затем возвращает управление вызывающей части программы. А когда метод Add() вызывается для ограниченной коллекции, он блокирует доступ к ней, если она заполнена. После того как из коллекции будет удален один элемент или больше, указанный элемент item будет добавлен в коллекцию, и затем произойдет возврат из данного метода. Метод Таке() удаляет элемент из коллекции и возвращает управление вызывающей части программы. (Имеются также варианты обоих методов, принимающие в качестве параметра признак задачи как экземпляр объекта типа CancellationToken.)

Применяя методы Add() и Таке(), можно реализовать простой шаблон "поставщик-потребитель", как показано в приведенном ниже примере программы. В этой программе создается поставщик, формирующий символы от А до Z, а также потребитель, получающий эти символы. При этом создается коллекция типа BlockingCollection<T>, ограниченная 4 элементами.

// Простой пример коллекции типа BlockingCollection.

using System;

using System.Threading.Tasks;

using System.Threading;

using System.Collections.Concurrent;

class BlockingDemo {

  static BlockingCollection<char> bc;

  // Произвести и поставить символы от А до Z.

  static void Producer() {

    for(char ch = 'A'; ch <= 'Z'; ch++) {

      bc.Add(ch);

      Console.WriteLine ("Производится символ " + ch) ;

    }

  }

  // Потребить 26 символов,

  static void Consumer() {

    for(int i=0; i < 26; i++)

    Console .WriteLine ("Потребляется символ " + bc.Take());

  }

  static void Main() {

    // Использовать блокирующую коллекцию, ограниченную 4 элементами,

    bc = new BlockingCollection<char>(4);

    // Создать задачи поставщика и потребителя.

    Task Prod = new Task(Producer);

    Task Con = new Task(Consumer);

    // Запустить задачи.

    Con.Start();

    Prod.Start();

    // Ожидать завершения обеих задач,

    try {

      Task.WaitAll(Con, Prod);

    } catch(AggregateException exc) {

      Console.WriteLine (exc);

    } finally {

      Con.Dispose();

      Prod.Dispose();

      bc.Dispose();

    }

  }

}

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