Namespaces
Variants

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

С ru.cppreference.net
 
 
Библиотека алгоритмов
Ограниченные алгоритмы и алгоритмы над диапазонами (C++20)
Ограниченные алгоритмы, напр. ranges::copy, ranges::sort, ...
Операции последовательности без изменения    
Пакетные операции
(C++17)
Операции поиска
Операции последовательности с изменением
Операции копирования
(C++11)
(C++11)
Операции обмена
Операции преобразования
Операции генерации
Операции удаления
Операции изменения порядка
(до C++17)(C++11)
(C++20)(C++20)
Операции выборки
(C++17)

Сортировка и связанные операции
Операции разбиения
(C++11)    

Операции сортировки
Операции бинарного поиска
(по разбитым диапазонам)
Операции над множествами (по отсортированным диапазонам)
Операции слияния (по отсортированным диапазонам)
Операции с кучей
Операции минимума/максимума
(C++11)
(C++17)
Операции лексикографического сравнения
Операции перестановок


Политики выполнения (C++17)
(только для демонстрации*)(C++26)

Числовые операции
(C++11)
(C++17)
(C++17)    

Специализированные <memory> алгоритмы

Специализированные <random> алгоритмы
Библиотека C









 
Определено в заголовочном файле <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)
1) Тип политики выполнения, используемый как уникальный тип для разрешения перегрузки параллельных алгоритмов и требующий, чтобы выполнение параллельного алгоритма не было распараллелено. Вызовы функций доступа к элементам в параллельных алгоритмах, вызываемых с этой политикой (обычно задаваемой как std::execution::seq), являются недетерминированно последовательными в вызывающем потоке.
2) Тип политики выполнения, используемый как уникальный тип для разрешения перегрузки параллельных алгоритмов и указывающий, что выполнение параллельного алгоритма может быть распараллелено. Вызовы функций доступа к элементам в параллельных алгоритмах, вызываемых с этой политикой (обычно задаваемой как std::execution::par), могут выполняться либо в вызывающем потоке, либо в потоке, неявно созданном библиотекой для поддержки выполнения параллельного алгоритма. Любые такие вызовы, выполняющиеся в одном и том же потоке, являются недетерминированно последовательными друг относительно друга. Если потоки выполнения, созданные std::thread или std::jthread, предоставляют гарантии конкурентного продвижения, то потоки выполнения, созданные библиотекой, предоставляют гарантии параллельного продвижения. В противном случае предоставляемая гарантия продвижения определяется реализацией. Примечание: гарантии параллельного продвижения означают, что если поток выполнения делает шаг, он в конечном итоге сделает ещё один шаг, что позволяет потокам входить в критические секции и захватывать блокировки, поскольку поток, владеющий блокировкой, в итоге снова будет запланирован и сможет её освободить.
3) Тип политики выполнения, используемый как уникальный тип для разрешения перегрузки параллельных алгоритмов и указывающий, что выполнение параллельного алгоритма может быть распараллелено, векторизовано или перенесено между потоками (например, планировщиком, использующим кражу родительских задач). Вызовы функций доступа к элементам в параллельных алгоритмах, вызываемых с этой политикой, могут выполняться неупорядоченно в неопределённых потоках и быть неупорядоченными друг относительно друга внутри каждого потока. Вызовы функций доступа к элементам в параллельных алгоритмах с этой политикой не должны вызывать операции, небезопасные для векторизации, такие как те, что стандартная библиотека определяет как синхронизирующие, включая операции std::atomic и другие примитивы параллелизма. Если потоки выполнения, созданные std::thread или std::jthread, предоставляют гарантии конкурентного продвижения, то потоки выполнения, созданные библиотекой, предоставляют гарантии слабого параллельного продвижения. В противном случае предоставляемая гарантия продвижения совпадает с гарантией потока, вызывающего параллельный алгоритм. Примечание: гарантии слабого параллельного продвижения означают, что один из потоков выполнения, сделавших шаг, в конечном итоге сделает ещё один шаг, что не позволяет потокам входить в критические секции или захватывать блокировки, поскольку поток, владеющий блокировкой, может не быть снова запланирован до тех пор, пока поток, пытающийся захватить блокировку, не завершится.
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); // Error: data race
});
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: assumes execution order
});
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; // correct
});

Неупорядоченные политики выполнения — это единственный случай, когда вызовы функций являются неупорядоченными друг относительно друга, то есть могут перемежаться. Во всех остальных ситуациях в C++ они являются недетерминированно-последовательными (не могут перемежаться). Из-за этого пользователям не разрешается выделять или освобождать память, захватывать мьютексы, использовать специализации std::atomic, не являющиеся lock-free, или, в целом, выполнять любые небезопасные для векторизации операции при использовании этих политик (функции, небезопасные для векторизации, — это те, которые синхронизируются с другой функцией, например, 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); // Error: lock_guard constructor calls m.lock()
    ++x;
});

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

См. также

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