Вопрос по Курсу: "Параллельное программирование с использованием MS VisualStudia 2010". При компиляции Самостоятельного задания (одновременная отрисовка прямоугольников, эллипсов и выдача в текст-бокс случайного числа) среда предупреждает: suspend - устаревшая команда; примените monitor, mutex и т.п. Создаётся впечатление, что Задание создано в более поздней среде, чем VS 2010. |
Параллельные коллекции. Низкоуровневая синхронизация
ConcurrentStack
ConcurrentStack представляет собой потокобезопасную коллекцию, обслуживаемую по принципу "последним поступил - первым обслужен" (LIFO). Данная коллекция похожа на коллекцию ConcurrentQueue, но с другими методами доступа к элементам. Класс ConcurrentStack определяет методы Push(), PushRange(), TryPeek(), TryPop() и TryPopRange(). Более подробно методы класса ConcurrentStack описаны в Табл. 15.4.
Имя | Описание |
---|---|
Push(T) | Добавляет объект в качестве верхнего элемента коллекции. |
PushRange(T[]) | Добавляет неделимым блоком несколько объектов в качестве верхнего элемента коллекции. |
PushRange(T[], int, int) | Добавляет неделимым блоком несколько объектов в качестве верхнего элемента коллекции. |
TryPeek(out T) | Пытается вернуть объект из начала коллекции ConcurrentStack без его удаления. |
TryPop(out T) | Пытается извлечь и вернуть верхний объект коллекции ConcurrentStack. |
TryPopRange(out T[]) | Пытается извлечь и вернуть несколько объектов из начала коллекции ConcurrentStack в виде неделимого блока. |
TryPopRange(out T[], int, int) | Пытается извлечь и вернуть несколько объектов из начала коллекции ConcurrentStack в виде неделимого блока. |
Пример использования коллекции ConcurrentStack представлен ниже:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Collections.Concurrent; using System.Collections; namespace ConcurrentStackExample { class Program { static void Main(string[] args) { // создаем коллекцию ConcurrentStack<int> sharedStack = new ConcurrentStack<int>(); // заполняем коллекцию в цикле с помощью метода Push for (int i = 0; i < 1000; i++) { sharedStack.Push(i); } // объявляем переменную-счетчик количества обработанных элементов int itemCount = 0; // создаем список задач Task[] tasks = new Task[10]; for (int i = 0; i < tasks.Length; i++) { // создаем задачу tasks[i] = new Task(() => { while (sharedStack.Count > 0) { Thread.Sleep(10); int queueElement; // удаляем элемент из коллекции с помощью метода TryPop bool gotElement = sharedStack.TryPop(out queueElement); // увеличиваем значение переменной и сохраняем результат if (gotElement) { Interlocked.Increment(ref itemCount); } } }); // запускаем новую задачу tasks[i].Start(); } // ожидаем завершения всех задач Task.WaitAll(tasks); // выводим на экран отчет о количестве обработанных элементов Console.WriteLine("Обработанно элементов: {0}", itemCount); Console.ReadLine(); } } }
увеличить изображение
Рис. 15.4. Результат выполнения программы использующую коллекцию ConcurrentStack
ConcurrentBag
Коллекция СoncurrentBag представляет собой потокобезопасную неупорядоченную коллекцию объектов и реализует концепцию отображения потоков на используемые внутренне массивы, и старается избежать блокировок. Для доступа к элементам применяются методы Add(), TryPeek() и TryTake() (Табл. 15.5). СoncurrentBag можно представить как набор очередей с двусторонним доступом (deque). Каждый поток при работе с коллекцией обращается к своей собственной очереди, добавляя и удаляя элементы с ее начала. Когда случается так, что очередь одного потока пуста, а ему нужно извлечь элемент, то он извлекает его из очереди соседнего потока, но уже не сначала очереди, а с противоположного конца очереди. Такой подход позволяет практически не пересекаться разным потокам по данным.
Имя | Описание |
---|---|
Add(T) | Добавляет объект в коллекцию. |
TryPeek(out T) | Пытается вернуть объект из коллекции без его удаления. |
TryTake(out T) | Пытается удалить и вернуть объект из коллекции |
Пример использование коллекции СoncurrentBag представлен ниже:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Collections.Concurrent; using System.Collections; namespace ConcurrentCollection { class Program { static void Main(string[] args) { // создаем коллекцию ConcurrentBag<int> sharedBag = new ConcurrentBag<int>(); // заполняем коллекцию в цикле с помощью метода Add for (int i = 0; i < 1000; i++) { sharedBag.Add(i); } // объявляем переменную-счетчик количества обработанных элементов int itemCount = 0; // создаем список задач Task[] tasks = new Task[10]; for (int i = 0; i < tasks.Length; i++) { // создаем задачу tasks[i] = new Task(() => { while (sharedBag.Count > 0) { Thread.Sleep(10); int queueElement; // удаляем элемент из коллекции с помощью метода TryTake bool gotElement = sharedBag.TryTake(out queueElement); // увеливам значение переменной и сохраняем результат if (gotElement) { Interlocked.Increment(ref itemCount); } } }); // запускаем новую задачу tasks[i].Start(); } // ожидаем завершения всех задач Task.WaitAll(tasks); // выводим на экран отчет о количестве обработанных элементов Console.WriteLine("Обработанно элементов: {0}", itemCount); Console.ReadLine(); } } }