|
Вопрос по Курсу: "Параллельное программирование с использованием 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();
}
}
}

