Параллельные контейнеры и объекты
Библиотека параллельных шаблонов (PPL) содержит несколько контейнеров и объектов, предоставляющих потокобезопасный доступ к элементам внутри них.
Параллельный контейнер предоставляет безопасный доступ к важнейшим операциям в режиме параллелизма.Функциональные возможности этих контейнеров аналогичны возможностям, предоставляемым библиотекой стандартных шаблонов (STL).Например concurrency::concurrent_vector похож на класс std::vector класса, за исключением, concurrent_vector класс позволяет добавлять элементы в параллельном режиме.Параллельные контейнеры рекомендуется использовать, если имеется параллельный код, требующий прав чтения и записи по отношению к одному и тому же контейнеру.
Параллельный объект совместно используется компонентами в режиме параллелизма.Процесс, вычисляющий состояние параллельного объекта в параллельном режиме, дает тот же результат, что и процесс, вычисляющий то же состояние последовательно.Concurrency::combinable класса является примером типа объекта одновременно.Класс combinable позволяет выполнять вычисления параллельно, а затем объединять результаты этих вычислений в общий результат.Параллельные объекты следует использовать, если бы иначе для синхронизации доступа к общей переменной или ресурсу необходимо было бы использовать механизм синхронизации, например мьютекс.
Подразделы
В этом разделе подробно описываются следующие параллельные контейнеры и объекты.
Параллельные контейнеры
Класс concurrent_vector
Различия между классами concurrent_vector и vector
Безопасные операции в режиме параллелизма
Безопасность исключений
Класс concurrent_queue
Различия между классами concurrent_queue и queue
Безопасные операции в режиме параллелизма
Поддержка итераторов
Класс concurrent_unordered_map
Различия между concurrent_unordered_map и unordered_map
Безопасные операции в режиме параллелизма
Класс concurrent_unordered_multimap
Класс concurrent_unordered_set
Класс concurrent_unordered_multiset
Параллельные объекты
Класс combinable
Методы и свойства
Примеры
Класс concurrent_vector
Concurrency::concurrent_vector класс является классом контейнер последовательности, так же, как std::vector класса, позволяет случайным образом получить доступ к его элементам.Класс concurrent_vector позволяет безопасно осуществлять операции добавления элементов и доступа к этим элементам в режиме параллелизма.Операции добавления не делают недействительными существующие указатели или итераторы.Операции доступа к итераторам и прохождения итераторов также являются безопасными в режиме параллелизма.
Различия между классами concurrent_vector и vector
Класс concurrent_vector во многом напоминает класс vector.Сложность операций добавления, доступа к элементам и итераторам для объекта concurrent_vector та же, что и для объекта vector.Далее показано, чем класс concurrent_vector отличается от vector.
Операции добавления, доступа к элементу или итератору и прохождения итератора в объекте concurrent_vector являются безопасными в режиме параллелизма.
Добавлять элементы можно только в конец объекта concurrent_vector.Класс concurrent_vector не предоставляет метод insert.
При выполнении присоединения объект concurrent_vector не использует семантику перемещения.
Класс concurrent_vector не предоставляет методы erase и pop_back.Как и с vector, для удаления всех элементов из объекта concurrent_vector следует использовать метод clear.
Класс concurrent_vector не хранит в памяти все элементы подряд.Поэтому класс concurrent_vector невозможно использовать всеми способами, которыми используется массив.Например, для переменной с именем v типа concurrent_vector выражение &v[0]+2 выдает неопределенное поведение.
Класс concurrent_vector определяет методы grow_by и grow_to_at_least.Эти методы аналогичны методу resize, но при этом их можно безопасно использовать в режиме параллелизма.
Объект concurrent_vector не изменяет расположение элементов при добавлении в объект новых элементов или изменении его размеров.Благодаря этому существующие указатели и итераторы остаются действительными при выполнении параллельных операций.
Среда выполнения не определяет специальную версию concurrent_vector для типа bool.
Безопасные операции в режиме параллелизма
Все методы, добавляющие элементы в объект concurrent_vector, увеличивающие его размер или осуществляющие доступ к элементу в объекте concurrent_vector, являются безопасными в режиме параллелизма.Исключением из этого правила является метод resize.
В следующей таблице представлены наиболее распространенные методы и операторы класса concurrent_vector, являющиеся безопасными в режиме параллелизма.
Операции, которые среда выполнения предоставляет для совместимости с STL, например, reserve, не являются безопасным параллелизма.В следующей таблице представлены наиболее распространенные методы и операторы, не являющиеся безопасными в режиме параллелизма.
Операции, изменяющие значение существующих элементов, не являются безопасными в режиме параллелизма.Для синхронизации параллельных операций чтения и записи в один и тот же элемент данных необходимо использовать объект синхронизации, такой как reader_writer_lock.Дополнительные сведения об объектах синхронизации см. в разделе Структуры данных синхронизации.
При преобразовании существующего кода, использующего vector, для использования concurrent_vector, параллельные операции могут стать причиной изменения поведения приложения.Рассмотрим следующую программу, параллельно выполняющую две задачи с объектом concurrent_vector.Первая задача добавляет элементы в объект concurrent_vector.Вторая задача вычисляет сумму всех элементов в этом объекте.
// parallel-vector-sum.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_vector.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
// Create a concurrent_vector object that contains a few
// initial elements.
concurrent_vector<int> v;
v.push_back(2);
v.push_back(3);
v.push_back(4);
// Perform two tasks in parallel.
// The first task appends additional elements to the concurrent_vector object.
// The second task computes the sum of all elements in the same object.
parallel_invoke(
[&v] {
for(int i = 0; i < 10000; ++i)
{
v.push_back(i);
}
},
[&v] {
combinable<int> sums;
for(auto i = begin(v); i != end(v); ++i)
{
sums.local() += *i;
}
wcout << L"sum = " << sums.combine(plus<int>()) << endl;
}
);
}
Хотя метод end является безопасным в режиме параллелизма, параллельный вызов метода push_back вызывает изменение значения, возвращаемого методом end.Число элементов, проходимых итератором, определить невозможно.Поэтому программа может выдавать разные результаты при каждом запуске.
Безопасность исключений
Если при выполнении операции увеличения или назначения создается исключение, состояние объекта concurrent_vector становится недействительным.Поведение объекта concurrent_vector, находящегося в недействительном состоянии, является неопределенным, если не указано иное.Однако деструктор всегда освобождает память, выделяемую объектом, даже если объект находится в недействительном состоянии.
Тип данных элементов класса vector, _Ty, должен соответствовать следующим требованиям.В противном случае поведение класса concurrent_vector не определено.
Деструктор не должен создавать исключения.
Если конструктор по умолчанию или конструктор копии создает исключение, не следует использовать ключевое слово virtual для объявления деструктора, который, кроме того, должен правильно работать с инициализированной с нуля памятью.
Top
Класс concurrent_queue
Concurrency::concurrent_queue класса так же, как std::queue класса, позволяет доступ к его передней и задней элементов.Класс concurrent_queue позволяет безопасно выполнять операции постановки в очередь и удаления из очереди в режиме параллелизма.Класс concurrent_queue также обеспечивает поддержку итераторов, не являющихся безопасными в режиме параллелизма.
Различия между классами concurrent_queue и queue
Класс concurrent_queue во многом напоминает класс queue.Далее показано, чем класс concurrent_queue отличается от класса queue.
Операции постановки в очередь и удаления из очереди в объекте concurrent_queue являются безопасными в режиме параллелизма.
Класс concurrent_queue обеспечивает поддержку итераторов, не являющихся безопасными в режиме параллелизма.
Класс concurrent_queue не предоставляет методы front и pop.Класс concurrent_queue заменяет эти методы, определяя метод try_pop.
Класс concurrent_queue не предоставляет метод back.Следовательно, нельзя ссылаться на конец очереди.
Класс concurrent_queue предоставляет метод unsafe_size вместо метода size.Метод unsafe_size не является безопасным в режиме параллелизма.
Безопасные операции в режиме параллелизма
Все методы, помещающие элементы в очередь или удаляющие их из очереди в объекте concurrent_queue, являются безопасными в режиме параллелизма.
В следующей таблице представлены наиболее распространенные методы и операторы класса concurrent_queue, являющиеся безопасными в режиме параллелизма.
Хотя метод empty является безопасным в режиме параллелизма, параллельная операция может стать причиной увеличения или уменьшения очереди до возвращения метода empty.
В следующей таблице представлены наиболее распространенные методы и операторы, не являющиеся безопасными в режиме параллелизма.
Поддержка итераторов
Класс concurrent_queue предоставляет итераторы, которые не являются безопасными в режиме параллелизма.Эти итераторы рекомендуется использовать только для отладки.
Итератор concurrent_queue проходит элементы только в прямом направлении.В следующей таблице показаны операторы, которые поддерживаются каждым итератором.
Оператор |
Описание |
---|---|
Переходит к следующему элементу в очереди.Этот оператор перегружается, чтобы обеспечить семантику префиксного и постфиксного приращений. |
|
Извлекает ссылку на текущий элемент. |
|
Извлекает указатель на текущий элемент. |
Top
Класс concurrent_unordered_map
Concurrency::concurrent_unordered_map класс является ассоциативный контейнера, так же, как std::unordered_map класс, управляющий разной длины последовательность элементов типа std::pair < const ключ, Ty >.Неупорядоченные карты можно рассматривать как словарь, который можно добавить пару ключ-значение для или искать значение по ключу.Этот класс полезен, когда имеется несколько потоков или задач, которые должны одновременно доступ к общим контейнера, вставьте в него или его обновления.
Следующий пример показывает базовую структуру для использования concurrent_unordered_map.В этом примере вставляет символ ключи в диапазоне [«», ' i'].Поскольку порядок операций не определено, конечное значение для каждого ключа также не определено.Тем не менее является безопасным для выполнения операций вставки в параллельном режиме.
// unordered-map-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_map.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
//
// Insert a number of items into the map in parallel.
concurrent_unordered_map<char, int> map;
parallel_for(0, 1000, [&map](int i) {
char key = 'a' + (i%9); // Geneate a key in the range [a,i].
int value = i; // Set the value to i.
map.insert(make_pair(key, value));
});
// Print the elements in the map.
for_each(begin(map), end(map), [](const pair<char, int>& pr) {
wcout << L"[" << pr.first << L", " << pr.second << L"] ";
});
}
/* Sample output:
[e, 751] [i, 755] [a, 756] [c, 758] [g, 753] [f, 752] [b, 757] [d, 750] [h, 754]
*/
Пример, использующий concurrent_unordered_map карты и уменьшить операции параллельно, см. Практическое руководство. Параллельное выполнение операций сопоставления и сокращения числа элементов.
Различия между concurrent_unordered_map и unordered_map
Класс concurrent_unordered_map во многом напоминает класс unordered_map.Далее показано, чем класс concurrent_unordered_map отличается от unordered_map.
The erase, bucket, bucket_count, and bucket_size methods are named unsafe_erase, unsafe_bucket, unsafe_bucket_count, and unsafe_bucket_size, respectively.unsafe_ Соглашение об именах указывает, что эти методы не одновременности.Дополнительные сведения о безопасности параллельной обработки, см. Параллелизма строго типизированные операции.
Операций вставки не нарушают существующих указателей или итераторов, а также их изменить порядок элементов, которые уже существуют в области схемы.Вставка и обзор операции могут выполняться одновременно.
concurrent_unordered_mapподдерживает пересылку только итерации.
Вставка недействительными или не обновлять итераторы, возвращаемые equal_range.Конец диапазона вставки можно добавить несовпадение элементов.Начало итератором равно элемента.
Чтобы избежать взаимоблокировки, метод не concurrent_unordered_map удерживает блокировку вызывает распределитель памяти, функции хэширования или другой пользовательский код.Кроме того необходимо убедиться, хэш-функция всегда равно равно ключи совпадают.Наиболее хеш-функции равномерно распределять ключи по места код хэша.
Безопасные операции в режиме параллелизма
concurrent_unordered_map Класс позволяет параллелизма строго типизированные операции вставки и доступа к элементу.Операции вставки недействительными существующие указатели или итераторов.Операции доступа к итераторам и прохождения итераторов также являются безопасными в режиме параллелизма.В следующей таблице перечислены часто используемые concurrent_unordered_map методов и операторов, которые являются одновременности.
count |
find |
||
begin |
empty |
get_allocator |
max_size |
cbegin |
end |
hash_function |
|
cend |
equal_range |
size |
Хотя count безопасный метод может быть вызван из одновременно выполняющихся потоков, различные потоки могут получать разные результаты, если новое значение одновременно вставить в контейнер.
Ниже приведены наиболее часто используемых методов и операторов, которые не являются безопасным параллелизма.
clear |
max_load_factor |
rehash |
load_factor |
Помимо этих методов любого метода, начинается с unsafe_ также не является типизированным параллелизма.
Top
Класс concurrent_unordered_multimap
Concurrency::concurrent_unordered_multimap класс похож на concurrent_unordered_map класса, за исключением того, что позволяет несколько значений для сопоставления с тем же ключом.Он также отличается от concurrent_unordered_map следующим образом:
Concurrent_unordered_multimap::insert метод возвращает итератор вместо std::pair<iterator, bool>.
concurrent_unordered_multimap Класс не предоставляет operator[] , ни at метод.
Следующий пример показывает базовую структуру для использования concurrent_unordered_multimap.В этом примере вставляет символ ключи в диапазоне [«», ' i'].concurrent_unordered_multimapпозволяет иметь несколько значений ключа.
// unordered-multimap-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_map.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
//
// Insert a number of items into the map in parallel.
concurrent_unordered_multimap<char, int> map;
parallel_for(0, 10, [&map](int i) {
char key = 'a' + (i%9); // Geneate a key in the range [a,i].
int value = i; // Set the value to i.
map.insert(make_pair(key, value));
});
// Print the elements in the map.
for_each(begin(map), end(map), [](const pair<char, int>& pr) {
wcout << L"[" << pr.first << L", " << pr.second << L"] ";
});
}
/* Sample output:
[e, 4] [i, 8] [a, 9] [a, 0] [c, 2] [g, 6] [f, 5] [b, 1] [d, 3] [h, 7]
*/
Top
Класс concurrent_unordered_set
Concurrency::concurrent_unordered_set класс похож на concurrent_unordered_map класса, за исключением того, что он управляет значений вместо пары "ключ-значение".concurrent_unordered_set Класс не предоставляет operator[] , ни at метод.
Следующий пример показывает базовую структуру для использования concurrent_unordered_set.В этом примере вставляет значения символов в диапазоне [«», ' i'].Безопасно для выполнения операций вставки в параллельном режиме.
// unordered-set-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_set.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
//
// Insert a number of items into the set in parallel.
concurrent_unordered_set<char> set;
parallel_for(0, 10000, [&set](int i) {
set.insert('a' + (i%9)); // Geneate a value in the range [a,i].
});
// Print the elements in the set.
for_each(begin(set), end(set), [](char c) {
wcout << L"[" << c << L"] ";
});
}
/* Sample output:
[e] [i] [a] [c] [g] [f] [b] [d] [h]
*/
Top
Класс concurrent_unordered_multiset
Concurrency::concurrent_unordered_multiset класс похож на concurrent_unordered_set класса, но разрешает повторяющиеся значения.Он также отличается от concurrent_unordered_set следующим образом:
Concurrent_unordered_multiset::insert метод возвращает итератор вместо std::pair<iterator, bool>.
concurrent_unordered_multiset Класс не предоставляет operator[] , ни at метод.
Следующий пример показывает базовую структуру для использования concurrent_unordered_multiset.В этом примере вставляет значения символов в диапазоне [«», ' i'].concurrent_unordered_multisetвключает значение возникает несколько раз.
// unordered-set-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_set.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
//
// Insert a number of items into the set in parallel.
concurrent_unordered_multiset<char> set;
parallel_for(0, 40, [&set](int i) {
set.insert('a' + (i%9)); // Geneate a value in the range [a,i].
});
// Print the elements in the set.
for_each(begin(set), end(set), [](char c) {
wcout << L"[" << c << L"] ";
});
}
/* Sample output:
[e] [e] [e] [e] [i] [i] [i] [i] [a] [a] [a] [a] [a] [c] [c] [c] [c] [c] [g] [g]
[g] [g] [f] [f] [f] [f] [b] [b] [b] [b] [b] [d] [d] [d] [d] [d] [h] [h] [h] [h]
*/
Top
Класс combinable
Concurrency::combinable класс предоставляет хранилище для многократного использования, локальной памяти потока, позволяет выполнять вычисления детализированное и затем объединить эти вычисления конечного результата.Объект combinable можно сравнить с переменной сокращения.
Класс combinable полезно использовать, если имеется ресурс, совместно используемый в нескольких потоках или задачах.Класс combinable помогает исключить состояние с общим доступом, предоставляя доступ к общим ресурсам без блокировок.Следовательно, этот класс предоставляет альтернативу механизму синхронизации, например мьютексу, для синхронизации доступа к общим данным из различных потоков.
Методы и свойства
В следующей таблице показаны некоторые важные методы, принадлежащие к классу combinable.Дополнительные сведения о всех методах класса combinable см. в разделе Класс combinable.
Метод |
Описание |
---|---|
Извлекает ссылку на локальную переменную, связанную с текущим контекстом потока. |
|
Удаляет все локальные переменные потока из объекта combinable. |
|
Использует предоставленную функцию combine для создания окончательного значения из набора локальных вычислений потока. |
Класс combinable является классом шаблона, который параметризуется по окончательному результату слияния.Если вызывается конструктор по умолчанию, тип параметров шаблона _Ty должен иметь конструктор по умолчанию и конструктор копии.Если тип параметров шаблона _Ty не имеет конструктора по умолчанию, необходимо вызвать версию перегрузки конструктора, принимающую в качестве параметра функцию инициализации.
После вызова метода combine или combine_each в объекте combinable можно хранить дополнительные данные.Кроме того, методы combine и combine_each можно вызывать несколько раз.Если в объекте combinable не меняется локальное значение, методы combine и combine_each дают при каждом вызове один и тот же результат.
Примеры
Примеры использования класса combinable см. в следующих разделах.
Практическое руководство. Использование класса combinable для повышения производительности
Практическое руководство. Использование объекта combinable для комбинирования наборов
Top
Связанные разделы
Практическое руководство. Использование параллельных контейнеров для повышения эффективности
Показывает использование параллельных контейнеров для эффективного хранения данных и доступа к данным в параллельном режиме.Практическое руководство. Использование класса combinable для повышения производительности
Показывает использование класса combinable для исключения состояния с общим доступом и, следовательно, повышения производительности.Практическое руководство. Использование объекта combinable для комбинирования наборов
Показывает использование функции combine для слияния локальных наборов данных потока.Библиотека параллельных шаблонов
Описывает библиотеку PPL, которая предоставляет императивную модель программирования, способствующую масштабируемости и простоте разработки параллельных приложений.
Ссылки
Класс concurrent_unordered_map
Класс concurrent_unordered_multimap
Класс concurrent_unordered_set