Пространства имён
Варианты
Действия

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

Материал из cppreference.com
 
 
Библиотека алгоритмов
Ограниченные алгоритмы и алгоритмы над диапазонами (C++20)
Ограниченные алгоритмы, например ranges::copy, ranges::sort, ...
Политики исполнения (C++17)
Немодифицирующие операции над последовательностями
(C++11)(C++11)(C++11)
(C++17)
Модифицирующие операции над последовательностями
Операции разбиения
Операции сортировки
(C++11)
Операции двоичного поиска
Операции с наборами (в отсортированных диапазонах)
Операции с кучей
(C++11)
Операций минимума/максимума
(C++11)
(C++17)

Операции перестановки
Числовые операции
Операции с неинициализированной памятью
(C++17)
(C++17)
(C++17)
Библиотека C
 
<tbody> </tbody>
Определено в заголовочном файле <execution>
class sequenced_policy { /* не определено */ };
(1) (начиная с C++17)
class parallel_policy { /* не определено */ };
(2) (начиная с C++17)
class parallel_unsequenced_policy { /* не определено */ };
(3) (начиная с C++17)
class unsequenced_policy { /* не определено */ };
(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); // Ошибка: гонка данных
});
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) { }
});
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; // правильно
});

Непоследовательные политики выполнения это единственный случай, когда вызовы функций непоследовательны по отношению друг к другу, что означает, что они могут чередоваться. Во всех других ситуациях в 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)
{
    // Ошибка: конструктор lock_guard вызывает m.lock()
    std::lock_guard<std::mutex> guard(m);
    ++x;
});

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

Смотрите также

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