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以降) |
これらの実行ポリシーのいずれかを使用した並列アルゴリズムの実行中に、要素アクセス関数の呼び出しが捕捉されない例外によって終了した場合、 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; });
実装が並列化またはベクトル化できない場合(例:リソース不足のため)、すべての標準実行ポリシーは逐次実行にフォールバックすることができます。
関連項目
|
(C++17)
(C++17)
(C++17)
(C++20)
|
グローバル実行ポリシーオブジェクト
(定数) |