Чтение онлайн

ЖАНРЫ

C# 4.0 полное руководство - 2011

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

Шрифт:

Когда метод 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> be;

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

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

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

}

}

// Потребить 26 символов, static void Consumer {

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

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

}

static void Main {

// Использовать блокирующую коллекцию, ограниченную 4 элементами, be = 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 ; be.Dispose;

}

}

}

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

Кроме того, попробуйте ограничить коллекцию одним элементом. В этом случае одновременно может быть сформирован лишь один элемент.

Для работы с коллекцией типа BlockingCollection<T> может оказаться полезным и метод CompleteAdding . Ниже приведена форма его объявления.

public void CompleteAdding

Вызов этого метода означает, что в коллекцию не будет больше добавлено ни одного элемента. Это приводит к тому, что свойство IsAddingComplete принимает логическое значение true. Если же коллекция пуста, то свойство IsCompleted принимает логическое значение true, и в этом случае вызовы метода Таке не блокируются. Ниже приведены формы объявления свойств IsAddingComplete и IsCompleted.

public bool IsCompleted { get; } public bool IsAddingComplete { get; }

Когда коллекция типа BlockingCollection<T> только начинает формироваться, эти свойства содержат логическое значение false. А после вызова метода CompleteAdding они принимают логическое значение true.

Ниже приведен вариант предыдущего примера программы, измененный с целью продемонстрировать применение метода CompleteAdding , свойства IsCompleted и метода TryTake .

// Применение методов CompleteAdding, TryTake и свойства IsCompleted. using System;

using System.Threading.Tasks;

using System.Threading;

using System.Collections.Concurrent;

class BlockingDemo {

static BlockingCollection<char> be;

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

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

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

}

be.CompleteAdding;

}

// Потреблять символы до тех пор, пока их будет производить поставщик.

static void Consumer {

char ch;

while(!be.IsCompleted) { if(be.TryTake(out ch))

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

}

}

static void Main {

// Использовать блокирующую коллекцию, ограниченную 4 элементами, be = new BlockingCollection<char>(4);

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

Task Prod = new Task(Producer);

Task Con = new Task(Consumer);

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

Con.Start;

Prod.Start;

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

Поделиться с друзьями: