乱序执行 - 它可以绕过控制语句吗?

时间:2013-07-02 19:20:42

标签: c compiler-construction cpu sync

关于OOO,我们假设我只有一个进程(有一个线程)运行此代码:

void foo() {

    if (x == 0) {
        return;
    }

    y->data = 5;

}

现在,我们假设我知道 y仅在x不为零时才有效。 从硬件的角度来看,CPU可以在阅读y->data = 5之前执行x吗? 它可能导致CPU访问NULL /垃圾指针并崩溃。

如果没有,这是什么原因? 因为if / while / for / goto是控制语句,CPU在看到控制语句时不会提前获取指令吗?

我记得,OOO应该对执行其指令的一个线程100%透明。

2 个答案:

答案 0 :(得分:2)

取决于你如何看待它。

  • 从用户的角度来看,没有。
  • 从CPU的角度来看,是的。

从用户的角度来看,程序的行为必须“好像”它是按顺序运行的 换句话说,顺序运行和使用OOE运行之间没有明显的区别。 (除了表演)

从CPU的角度来看,是的,它实际上可以绕过if语句并执行y->data = 5;。但这是因为branch prediction而不是OOE。


在现代处理器上,线程可能会错误地预测分支:

if (x == 0) {
    return;
}

并且实际上尝试执行y->data = 5; ...

如果发生这种情况并且y是一个错误的指针,它将获得硬件异常,但由于执行仍处于推测模式,因此该异常被保留。

一旦线程意识到它错误预测了分支,它就会抛弃分支之外的所有内容(包括异常)。

所以最后,没有什么可担心的。即使处理器试图做某事它也不能,它也不会影响顺序行为。

换句话说,如果一个现代处理器造成一个不是你的错误的混乱,它将会自行清理。


当你有多个线程时,事情变得更加丑陋,但这超出了这个问题的范围。

答案 1 :(得分:0)

答案是:这取决于。

C标准描述了中的抽象机器,其中优化问题无关紧要。除了访问volatile对象之外,如果语句不改变程序的可观察行为,则可以自由地重新排序语句。 C11提出了该程序的可观察行为的定义:

  

(C11,5.1.2.3p6)“符合要求的实施的最低要求是:

     

- 严格按照摘要规则评估对易失性对象的访问   机。

     

- 程序终止时,写入文件的所有数据应与结果相同   根据抽象语义执行程序会产生。

     

- 交互设备的输入和输出动态应按照规定进行   7.21.3。这些要求的目的是无缓冲或行缓冲输出   尽快出现,以确保提示消息实际出现在之前   等待输入的程序。

     

这是程序“

的可观察行为

C11也有这一段(已经在C99中出现):

  

(C11,5.1.2.3p10)“或者,实现可以在每个翻译单元内执行各种优化,例如   只有在跨翻译单元边界进行函数调用时,实际语义才会与抽象语义一致。 [...]“

因此,在您的示例中,它实际上取决于y的声明方式(即,它的链接是什么?)以及它在程序中的使用方式。

重新排序实际上是由编译器在现实生活中使用,如果它认为它不会影响程序的可观察行为,则优化代码的某些部分。