std::execution::sequenced_policy, std::execution::parallel_policy, std::execution::parallel_unsequenced_policy, std::execution::unsequenced_policy
| Определено в заголовочном файле <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) |
Во время выполнения параллельного алгоритма с любой из этих политик выполнения, если вызов функции доступа к элементу завершается через неперехваченное исключение, вызывается 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) |
глобальные объекты политики выполнения (константа) |