Namespaces
Variants

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

From cppreference.net
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy , ranges::sort , ...
Execution policies (C++17)
execution::sequenced_policy execution::parallel_policy execution::parallel_unsequenced_policy execution::parallel_unsequenced
(C++17) (C++17) (C++17) (C++20)
Non-modifying sequence operations
Batch operations
(C++17)
Search operations
Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17) (C++11)
(C++20) (C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Lexicographical comparison operations
Permutation operations
C library
Numeric operations
Operations on uninitialized memory
Definido en el encabezado <execution>
class sequenced_policy { /* no especificado */ } ;
(1) (desde C++17)
class parallel_policy { /* no especificado */ } ;
(2) (desde C++17)
class parallel_unsequenced_policy { /* no especificado */ } ;
(3) (desde C++17)
class unsequenced_policy { /* no especificado */ } ;
(4) (desde C++20)
1) El tipo de política de ejecución utilizado como un tipo único para eliminar la ambigüedad en la sobrecarga de algoritmos paralelos y requerir que la ejecución de un algoritmo paralelo no pueda ser paralelizada. Las invocaciones de funciones de acceso a elementos en algoritmos paralelos invocados con esta política (generalmente especificada como std::execution::seq ) están secuenciadas de manera indeterminada en el hilo de llamada.
2) El tipo de política de ejecución utilizado como un tipo único para eliminar la ambigüedad en la sobrecarga de algoritmos paralelos e indicar que la ejecución de un algoritmo paralelo puede ser paralelizada. Las invocaciones de funciones de acceso a elementos en algoritmos paralelos invocados con esta política (generalmente especificada como std::execution::par ) están permitidas para ejecutarse en el hilo invocante o en un hilo creado implícitamente por la biblioteca para soportar la ejecución de algoritmos paralelos. Cualquier invocación de este tipo que se ejecute en el mismo hilo está indeterminadamente secuenciada con respecto a las demás. Si los hilos de ejecución creados por std::thread o std::jthread proporcionan garantías de progreso concurrente hacia adelante, entonces los hilos de ejecución creados por la biblioteca proporcionan garantías de progreso paralelo hacia adelante. De lo contrario, la garantía de progreso hacia adelante proporcionada está definida por la implementación. Nota: las garantías de progreso paralelo hacia adelante aseguran que si un hilo de ejecución da un paso, eventualmente dará otro paso, permitiendo que los hilos entren en secciones críticas y tomen bloqueos, porque el hilo que tiene el bloqueo eventualmente será programado nuevamente y podrá liberarlo.
3) El tipo de política de ejecución utilizado como tipo único para eliminar ambigüedades en la sobrecarga de algoritmos paralelos e indicar que la ejecución de un algoritmo paralelo puede ser paralelizada, vectorizada o migrada entre hilos (como mediante un planificador de robo de padres). Las invocaciones de funciones de acceso a elementos en algoritmos paralelos invocados con esta política están permitidas para ejecutarse de forma desordenada en hilos no especificados, y sin secuenciar entre sí dentro de cada hilo. Las invocaciones de funciones de acceso a elementos en algoritmos paralelos invocados con esta política no están permitidas para invocar operaciones no seguras para vectorización, como aquellas especificadas por la biblioteca estándar para sincronizar, incluyendo las de std::atomic y otras primitivas de concurrencia. Si los hilos de ejecución creados por std::thread o std::jthread proporcionan garantías de progreso concurrente hacia adelante, entonces los hilos de ejecución creados por la biblioteca proporcionan garantías de progreso hacia adelante débilmente paralelo. De lo contrario, la garantía de progreso hacia adelante proporcionada es la del hilo que invoca el algoritmo paralelo. Nota: las garantías de progreso hacia adelante débilmente paralelo aseguran que uno de los hilos de ejecución que ha dado un paso eventualmente dará otro paso, lo que no permite a los hilos entrar en secciones críticas o tomar bloqueos, porque el hilo que tiene el bloqueo podría no ser programado nuevamente hasta que un hilo que está intentando tomar el bloqueo haya salido.
4) El tipo de política de ejecución utilizado como tipo único para eliminar la ambigüedad de la sobrecarga de algoritmos paralelos e indicar que la ejecución de un algoritmo paralelo puede ser vectorizada, por ejemplo, ejecutada en un solo hilo utilizando instrucciones que operan sobre múltiples elementos de datos.

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 elementos finaliza mediante una excepción no capturada, std::terminate es llamado, pero las implementaciones pueden definir políticas de ejecución adicionales que manejen las excepciones de manera diferente.

Notas

Al utilizar la política de ejecución en paralelo, es responsabilidad del programador evitar las condiciones de carrera y los bloqueos mutuos:

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 el 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 no secuenciadas son el único caso donde las llamadas a funciones están no secuenciadas entre sí, lo que significa que pueden entrelazarse. En todas las demás situaciones en C++, están indeterminadamente secuenciadas (no pueden entrelazarse). Debido a esto, los usuarios no pueden asignar o liberar memoria, adquirir mutexes, usar especializaciones no lock-free de std::atomic o, en general, realizar cualquier operación no segura para vectorización cuando usan estas políticas (las funciones no seguras para vectorización son aquellas que se sincronizan con otra función, por ejemplo std::mutex::unlock se sincroniza con la siguiente 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: el constructor de lock_guard llama a m.lock()
    ++x;
});

Si la implementación no puede paralelizar o vectorizar (por ejemplo, debido a la falta de recursos), todas las políticas de ejecución estándar pueden recurrir a la ejecución secuencial.

Véase también

(C++17) (C++17) (C++17) (C++20)
objetos globales de políticas de ejecución
(constante)