68

给定以下函数调用:

f(g(), h())

由于未指定函数参数的评估顺序(据我所知,在 C++11 中仍然如此),理论上是否可以并行执行g()实现h()

这种并行化只能启动g并且h已知是相当微不足道的(在最明显的情况下,仅访问其身体本地的数据),以免引入并发问题,但是,超出该限制,我看不到任何禁止它的东西.

那么,标准允许吗?即使只是按照假设规则?

(在这个答案中,Mankarse 另有说法;但是,他没有引用标准,我的通读[expr.call]也没有发现任何明显的措辞。)

4

4 回答 4

42

要求来自[intro.execution]/15

... 调用函数时 ... 调用函数(包括其他函数调用)中的每个求值,在被调用函数的主体执行之前或之后没有明确排序相对于调用函数 [脚注:换句话说,函数执行不会相互交错。]。

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

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

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

于 2012-11-18T23:50:31.327 回答
16

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

于 2012-11-18T19:25:45.427 回答
3

除非编译器确切地知道它们调用的 , 和任何东西g()是做什么的。h()

这两个表达式是函数调用,可能有未知的副作用。因此,将它们并行化可能会导致这些副作用的数据竞争。由于 C++ 标准不允许参数评估在表达式的任何副作用上导致数据竞争,因此编译器只有在知道不可能发生此类数据竞争时才能并行化它们。

这意味着遍历每个函数并查看它们所做的和/或调用的确切操作,然后跟踪这些函数等。在一般情况下,这是不可行的。

于 2012-11-18T19:24:45.813 回答
1

简单的答案:当函数被排序时,即使是不确定的,两者之间也不可能出现竞争条件,如果它们被并行化,则情况并非如此。即使是一对单行“微不足道”的功能也可以做到。

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


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

如果p是 and 共享的名称g,则以任何顺序h依次调用gandh将导致指向的值p不改变。如果它们是并行的,则读取*p和分配它可以在两者之间任意交错:

  1. g读取*p并找到值 1。
  2. f读取*p并找到值 1。
  3. g将 2 写入*p.
  4. f, 仍然使用它之前读取的值 1 将写入 0 到*p.

因此,当它们被并行化时,行为是不同的。

于 2012-11-21T06:23:43.470 回答