std算法和副作用的并行实现

Parallel implementations of std algorithms and side effects

本文关键字:并行 实现 副作用 算法 std      更新时间:2023-10-16

在阅读std::transform的标准文档时,我注意到在C++11之前,函子参数被要求没有副作用,而从C++11开始,该要求的限制性降低了——"op和binary_op不得使迭代器或子范围无效,也不得修改范围中的元素"。参见

http://en.cppreference.com/w/cpp/algorithm/transform

以及本标准第25.3.4节。cppreference.com上的网页也提到,"这些要求的目的是允许并行或无序实现std::transform"。

我不明白这段代码在C++11:中是否合法

std::vector<int> v(/* fill it with something */), v_transformed;
int foo = 0;
std::transform(v.begin(),v.end(),std::back_inserter(v_transformed),[&foo](const int &n) -> int {
    foo += 1;
    return n*2;
});

显然,如果std::transform在后台被并行化,我们将有多个对foo += 1的并发调用,这将是UB。但函子本身似乎并没有违反标准中列出的要求。

其他标准算法也可以问这个问题(我认为std::for_each除外,它明确表示迭代要按顺序执行)。

我误解什么了吗?

就我对C++11规范的理解而言,所有标准库函数都必须按顺序执行所有操作,前提是它们的效果对用户可见。特别是,所有"突变序列操作"都必须按顺序执行。

该标准的相关部分为§17.6.5.9/8:

除非另有规定,否则C++标准库函数应仅在当前线程内执行所有操作,前提是这些操作的效果对用户可见(1.10)。

当前定义算法的方式必须按顺序执行,除非实现能够证明并行执行不会改变语义。我可以想象未来会添加明确允许并发执行的算法,但它们将是不同的算法。

因此,C++11现在允许std::transform进行并行化,但这并不能保证您自己的代码可以安全地进行并行化。现在,是的,我想你必须保护你的数据变量。如果实现真的将std::transform并行化,我可以想象会有很多MT错误由此产生。