从理论上讲,C ++实现可以并行化两个函数参数的评估吗?

时间:2012-11-18 19:08:43

标签: c++ language-lawyer

给出以下函数调用:

f(g(), h())

因为函数参数的评估顺序是未指定的(据我所知,在C ++ 11中仍然是这种情况),理论上可以并行执行g()h()吗?

这样的并行化只能在gh已知相当微不足道(在最明显的情况下,仅访问其身体本地的数据),以便不引入并发问题但除了这个限制,我看不到任何禁止它的东西。

那么,标准是否允许它?即使只是按照as-if规则?

(在this answer中,Mankarse声称不然;但是,他没有引用标准,而我对[expr.call]的通读没有发现任何明显的措辞。)

4 个答案:

答案 0 :(得分:42)

要求来自[intro.execution]/15

  

...调用函数时...调用函数中的每个评估(包括其他函数调用)在执行被调用函数体之前或之后没有特别排序不确定地排序< / strong>关于被调用函数的执行[脚注:换句话说,函数执行不会相互交错。]。

因此g()的主体的任何执行都必须与h()的评估不确定地排序(即不重叠)(因为h()是调用函数中的表达式)。

这里的关键点是g()h()都是函数调用。

(当然,as-if规则意味着不能完全排除这种可能性,但它绝不应该以可能影响程序的可观察行为的方式发生。最多,这样的实现只会改变代码的性能特征。)

答案 1 :(得分:16)

只要您无法分辨,无论编译器如何评估这些函数完全取决于编译器。显然,对功能的评估不能涉及对共享的可变数据的任何访问,因为这会引入数据竞争。基本的指导原则是“似乎” - 规则和基本的可观察操作,即访问volatile数据,I / O操作,访问原子数据等。相关部分是1.9 [intro.execution ]

答案 2 :(得分:3)

除非编译器确切知道g()h()以及他们调用的任何内容。

这两个表达式是函数调用,可能有未知的副作用。因此,对它们进行并行化可能会导致这些副作用的数据竞争。由于C ++标准不允许参数评估导致表达式的任何副作用的数据争用,因此编译器只能在知道没有这样的数据争用的情况下并行化它们。

这意味着走过每个功能,看看他们做了什么和/或打电话,然后跟踪那些功能等。在一般情况下,这是不可行的。

答案 3 :(得分:1)

简单回答:当函数排序时,即使不确定,两者之间也不存在竞争条件,如果它们是并行化的则不是这样。即使是一对一行“琐碎”的功能也可以做到。

void g()
{
    *p = *p + 1;
}


void h()
{
    *p = *p - 1;
}

如果p是由gh共享的名称,则按任意顺序依次调用gh将导致值p指出不改变。如果它们是并行化的,*p的读取及其分配可以在两者之间任意交错:

  1. g读取*p并找到值1。
  2. f读取*p并找到值1。
  3. g将2写入*p
  4. f,仍然使用之前读取的值1将0写入*p
  5. 因此,并行化时行为是不同的。