std::execution::sequenced_policy, std::execution::parallel_policy, std::execution::parallel_unsequenced_policy, std::execution::unsequenced_policy
| Definido en el archivo de encabezado <execution>
|
||
class sequenced_policy { /* sin especificar */ }; |
(1) | (desde C++17) |
class parallel_policy { /* sin especificar */ }; |
(2) | (desde C++17) |
class parallel_unsequenced_policy { /* sin especificar */ }; |
(3) | (desde C++17) |
class unsequenced_policy { /* sin especificar */ }; |
(4) | (desde C++20) |
Durante la ejecución de un algoritmo paralelo con cualquiera de estas políticas de ejecución, si la invocación de una función de acceso a un elemento egresa mediante una excepción no atrapada, se llama a std::terminate, pero las implementaciones pueden definir políticas de ejecución adicionales que manejen las excepciones de distinta manera.
Notas
Es la responsibilidad del programador evitar carreras de datos y bloqueos mutuos al usar la política de ejecución paralela:
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: carrera de datos
});
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: asume orden de ejecución
});
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; // correcto
});
Las políticas de ejecución sin secuenciar son el único caso donde las llamadas a función son sin secuenciar entre sí, lo que significa que pueden intercalarse. En todas las demás situaciones en C++, son secuenciadas indeterminadamente (no pueden intercalarse). Por esa razón, no se permite a los usuarios que asignen o desasignen memoria, adquieran cerrojos de exclusión mutua (mutexes), utilicen especializaciones de std::atomic que no son libres de bloqueo, o en general, llevar a cabo cualquier operación no segura para vectorización al usar estas políticas (las operaciones no seguras para vectorización son aquellas que se sincronizan-con otra función; por ejemplo, std::mutex::unlock se sincroniza-con la próxima llamada a 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: constructor lock_guard llama a m.lock()
++x;
});
Si la implementación no puede paralelizar o vectorizar (por ejemplo, debido a una falta de recursos), todas las políticas de ejecución pueden recurrir a la política secuencial.
Véase también
(C++17)(C++17)(C++17)(C++20) |
Objetos de políticas de ejecución globales. (constante) |