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) |
При выполнении параллельного алгоритма с любой из этих политик выполнения, если вызов функции доступа к элементу завершается неперехваченным исключением, 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++ они являются неопределённо-упорядоченными (не могут перемежаться). Из-за этого пользователям запрещено выделять или освобождать память, захватывать мьютексы, использовать не lock-free 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); // Ошибка: конструктор lock_guard вызывает m.lock() ++x; });
Если реализация не может распараллелить или векторизовать (например, из-за нехватки ресурсов), все стандартные политики выполнения могут переключиться на последовательное выполнение.
Смотрите также
|
(C++17)
(C++17)
(C++17)
(C++20)
|
глобальные объекты политики выполнения
(константы) |