std::execution::sequenced_policy, std::execution::parallel_policy, std::execution::parallel_unsequenced_policy, std::execution::unsequenced_policy
来自 zh.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),元素访问函数的调用在调用线程中是不确定顺序的。
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;
});
如果实现无法并行化或向量化(例如由于资源不足),所有标准执行策略可以回退到顺序执行。
另请参见
(C++17)(C++17)(C++17)(C++20) |
全局执行策略对象 (常量) |