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

问题描述 投票:0回答:2

关于 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% 透明的。

c synchronization cpu
2个回答
2
投票

取决于你如何看待它。

  • 从用户的角度来看,不会。
  • 从CPU的角度来看,是的。

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

从CPU的角度来看,是的,它实际上可以绕过if语句并执行

y->data = 5;
。但这是因为分支预测而不是OOE。


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

if (x == 0) {
    return;
}

并实际尝试执行

y->data = 5;
...

如果发生这种情况并且

y
是一个坏指针,它将得到硬件异常,但由于执行仍处于推测模式,所以该异常被保留。

一旦线程意识到它错误地预测了分支,它将丢弃该分支之后的所有内容(包括异常)。

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

换句话说,如果现代处理器弄得一团乱,这不是你的错,它会自行清理。


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


0
投票

答案是:视情况而定。

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

可观察行为
提出了定义:

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

— 对易失性对象的访问严格按照抽象规则进行评估 机器。

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

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

这是程序可观察到的行为”

C11也有这段(已经存在于C99中):

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

因此,在您的示例中,它实际上取决于
y

的声明方式(即它的链接是什么?)以及它在程序中的使用方式。


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

© www.soinside.com 2019 - 2024. All rights reserved.