std::execution::sequenced_policy, std::execution::parallel_policy, std::execution::parallel_unsequenced_policy, std::execution::unsequenced_policy
ja.cppreference.net から
| ヘッダ <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 と指定される)で呼び出された並列アルゴリズムにおける要素アクセス関数の呼び出しは、呼び出しスレッド内で不定順序 (indeterminately sequenced) で行われます。
2) 並列アルゴリズムのオーバーロード解決を曖昧さなくし、並列アルゴリズムの実行が並列化されてもよいことを示すために使用される、一意な型としての実行ポリシー型。このポリシー(通常は std::execution::par と指定される)で呼び出された並列アルゴリズムにおける要素アクセス関数の呼び出しは、呼び出しスレッドまたは並列アルゴリズムの実行をサポートするためにライブラリによって暗黙的に作成されたスレッドのいずれかで実行することが許可されます。同じスレッドで実行されるそのような呼び出しは、互いに不定順序で行われます。std::thread または std::jthread によって作成された実行スレッドが並行前進保証 (concurrent forward progress guarantees) を提供する場合、ライブラリによって作成された実行スレッドは並列前進保証 (parallel forward progress guarantees) を提供します。そうでない場合、提供される前進保証は実装定義です。注: 並列前進保証は、実行スレッドがステップを進めた場合、最終的には別のステップを進めることを保証し、スレッドがクリティカルセクションに入りロックを取得することを可能にします。なぜなら、ロックを保持しているスレッドは最終的に再スケジュールされ、ロックを解放できるからです。
3) 並列アルゴリズムのオーバーロード解決を曖昧さなくし、並列アルゴリズムの実行が並列化、ベクトル化、またはスレッド間での移行(例えば、親によるタスク横取りスケジューラなどにより)が許可されることを示すために使用される、一意な型としての実行ポリシー型。このポリシーで呼び出された並列アルゴリズムにおける要素アクセス関数の呼び出しは、未指定のスレッドで順不同 (unordered) に実行され、各スレッド内では互いに非順序 (unsequenced) で実行されることが許可されます。このポリシーで呼び出された並列アルゴリズムにおける要素アクセス関数の呼び出しは、std::atomic やその他の並行処理プリミティブのものなど、標準ライブラリによって同期することが指定されているベクトル化非安全 (vectorization-unsafe) な操作を呼び出してはなりません。std::thread または std::jthread によって作成された実行スレッドが並行前進保証を提供する場合、ライブラリによって作成された実行スレッドは弱並列前進保証 (weakly parallel forward progress guarantees) を提供します。そうでない場合、提供される前進保証は並列アルゴリズムを呼び出したスレッドのそれとなります。注: 弱並列前進保証は、ステップを進めた実行スレッドのうちの1つが最終的に別のステップを進めることを保証しますが、スレッドがクリティカルセクションに入ったりロックを取得したりすることはできません。なぜなら、ロックを保持しているスレッドは、ロックを取得しようとしているスレッドが終了するまで再スケジュールされない可能性があるからです。
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
});
非順序実行ポリシーは、関数呼び出しが互いに 非順序 (unsequenced) である唯一のケースであり、つまりインターリーブされる可能性があります。C++ の他のすべての状況では、それらは 不定順序 (indeterminately-sequenced) です(インターリーブ不可)。そのため、ユーザーはこれらのポリシーを使用する際に、メモリの確保や解放、ミューテックスの取得、非ロックフリーな 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;
});
実装が並列化やベクトル化できない場合(例えばリソース不足のため)、すべての標準実行ポリシーは逐次実行にフォールバックできます。
関連項目
(C++17)(C++17)(C++17)(C++20) |
グローバル実行ポリシーオブジェクト (定数) |