Spec-Zone.ru › C++

std::execution::sequenced_policy, std::execution::parallel_policy, std::execution::parallel_unsequenced_policy, std::execution::unsequenced_policy

Определено в заголовке <execution>
class sequenced_policy { /* unspecified */ };
(1) (с C++17)
class parallel_policy { /* unspecified */ };
(2) (с C++17)
class parallel_unsequenced_policy { /* unspecified */ };
(3) (с C++17)
class unsequenced_policy { /* unspecified */ };
(4) (с C++20)
1) Тип политики выполнения, используемый в качестве уникального типа для устранения неоднозначности перегрузки алгоритмов параллельной обработки и для требования, чтобы выполнение алгоритма параллельной обработки не могло быть распараллелено. Вызовы функций доступа к элементам в алгоритмах параллельной обработки, вызванных с этой политикой (обычно заданной как std::execution::seq), выполняются с неопределённой последовательностью в потоке вызова.
2) Тип политики выполнения, используемый в качестве уникального типа для устранения неоднозначности перегрузки алгоритмов параллельной обработки и для указания возможности распараллеливания выполнения алгоритма параллельной обработки. Вызовы функций доступа к элементам в алгоритмах параллельной обработки, вызванных с этой политикой (обычно заданной как std::execution::par), могут выполняться либо в вызывающем потоке, либо в потоке, неявно созданном библиотекой для поддержки выполнения алгоритма параллельной обработки. Любые такие вызовы, выполняющиеся в одном потоке, выполняются с неопределённой последовательностью друг относительно друга.
3) Тип политики выполнения, используемый в качестве уникального типа для устранения неоднозначности перегрузки алгоритмов параллельной обработки и для указания возможности распараллеливания, векторизации или миграции выполнения через потоки (например, планировщиком с родительским кражей). Вызовы функций доступа к элементам в алгоритмах параллельной обработки, вызванных с этой политикой, могут выполняться в неупорядоченном порядке в неопределённых потоках и без последовательности друг относительно друга в каждом потоке.
4) Тип политики выполнения, используемый в качестве уникального типа для устранения неоднозначности перегрузки алгоритмов параллельной обработки и для указания возможности векторизации выполнения алгоритма, например, выполнения в одном потоке с использованием инструкций, работающих с несколькими элементами данных.

Во время выполнения алгоритма параллельной обработки с любой из этих политик выполнения, если вызов функции доступа к элементу завершается с помощью неперехваченного исключения, std::terminate вызывается, но реализации могут определять дополнительные политики выполнения, обрабатывающие исключения по-разному.

Примечания

При использовании политики параллельного выполнения программист несёт ответственность за избегание гонок данных и тупиков:

int a[] = {0, 1};
std::vector<int> v;
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int i)
{
    v.push_back(i * 2 + 1); // Error: data race
});
std::atomic<int> x {0};
int a[] = {1, 2};
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int)
{
    x.fetch_add(1, std::memory_order_relaxed);
    while (x.load(std::memory_order_relaxed) == 1) { } // Error: assumes execution order
});
int x = 0;
std::mutex m;
int a[] = {1, 2};
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int)
{
    std::lock_guard<std::mutex> guard(m);
    ++x; // correct
});

Политики выполнения без последовательности — единственный случай, когда вызовы функций не упорядочены друг относительно друга, что означает, что они могут быть чередующимися. Во всех остальных ситуациях в C++ они имеют неопределённую последовательность (нельзя чередовать). Из-за этого пользователям не разрешается выделять или освобождать память, получать мьютексы, использовать специализации std::atomic без блокировок или, вообще, выполнять любые операции, небезопасные для векторизации, при использовании этих политик (функции небезопасные для векторизации — это функции, которые синхронизируются с другой функцией, например, std::mutex::unlock синхронизируется со следующей std::mutex::lock).

int x = 0;
std::mutex m;
int a[] = {1, 2};
std::for_each(std::execution::par_unseq, std::begin(a), std::end(a), [&](int)
{
    std::lock_guard<std::mutex> guard(m); // Error: lock_guard constructor calls m.lock()
    ++x;
});

Если реализация не может распараллелить или векторизовать (например, из-за нехватки ресурсов), все стандартные политики выполнения могут перейти к последовательному выполнению.

См. также

seqparpar_unsequnseq
(C++17)(C++17)(C++17)(C++20)
глобальные объекты политики выполнения
(константа)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/algorithm/execution_policy_tag_t

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API