Spec-Zone.ru › C++

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)
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, не являющиеся свободными от блокировок, или в целом выполнять любые операции, небезопасные для векторизации (функции, небезопасные для векторизации, — это функции, синхронизирующиеся с другой функцией; например, 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;
});

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

См. также

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

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/execution_policy_tag_t

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API