std::execution::sequenced_policy, std::execution::parallel_policy, std::execution::parallel_unsequenced_policy, std::execution::unsequenced_policy - cppreference.com
提供: cppreference.com
<tbody> </tbody>
| ヘッダ |
||
|
|
(1) | (C++17以上) |
|
|
(2) | (C++17以上) |
|
|
(3) | (C++17以上) |
|
|
(4) | (C++20以上) |
1) 並列アルゴリズムのオーバーロードの曖昧性を解決し、並列アルゴリズムの実行が並列化されてはならないことを要求するために、一意な型として使用される実行ポリシー型です。 このポリシー (通常 std::execution::seq として指定されます) を用いて呼び出された並列アルゴリズムにおける要素アクセス関数の呼び出しは、呼び出し元スレッド内で不定の順序に配列されます。
2) 並列アルゴリズムのオーバーロードの曖昧性を解決し、並列アルゴリズムの実行が並列化されても構わないことを示すために、一意な型として使用される実行ポリシー型です。 このポリシー (通常 std::execution::par として指定されます) を用いて呼び出された並列アルゴリズムにおける要素アクセス関数の呼び出しは、呼び出し元スレッド、または並列アルゴリズムの実行をサポートするためにライブラリによって暗黙に作成されたスレッドのいずれかで実行することが許されます。 同じスレッド内で実行されるあらゆるそのような呼び出しは、お互い不定の順序に配列されます。
3) 並列アルゴリズムのオーバーロードの曖昧性を解決し、並列アルゴリズムの実行が並列化されたり、ベクトル化されたり、あるいは (ペアレントスティーリングスケジューラなどによって) スレッド間で移送されたりしても構わないことを示すために、一意な型として使用される実行ポリシー型です。 このポリシーを用いて呼び出された並列アルゴリズムにおける要素アクセス関数の呼び出しは、未規定のスレッドで、各スレッド内の他のアクセスに対しても配列されず、順序付けされない方法で実行されることが許されます。
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); // エラー (データ競合) });
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) { std::lock_guard<std::mutex> guard(m); // エラー (lock_guard のコンストラクタは m.lock() を呼びます) ++x; });
処理系が並列化またはベクトル化できない場合 (例えばリソースが不足している)、すべての標準の実行ポリシーは逐次実行にフォールバックできます。