【发布时间】:2011-12-26 21:00:50
【问题描述】:
考虑以下代码:
volatile int a;
volatile int b;
int x;
void func() {
a = 1;
x = 0; /* dummy statement */
b = 2;
}
在这段代码 sn-p 中,对 x 的赋值构成了一个序列点。因此,根据 C90 标准,对 volatile 变量 a 的访问必须在开始访问 b 之前完成。将这段代码翻译成x86-64汇编时,函数体翻译如下:
movl $1, a(%rip)
movl $0, x(%rip)
movl $2, b(%rip)
现在,当执行此代码时,CPU 可能会重新排序内存访问,从而打破了 C 标准对 a 和 b 的访问按顺序执行的要求。那么,这种翻译是不是不正确,编译器不是必须插入内存屏障来强制排序吗?
编辑: 考虑 a 和 b 是两个线程共享的变量的情况。在这种情况下,两个线程之间的同步协议可能依赖于对 a 和 b 的访问按顺序发生的事实。因此,当 CPU 重新排序访问时,这可能会破坏该协议(我实际上并没有尝试实现这样的协议,我只是想知道 C 标准的正确解释是什么)。
【问题讨论】:
-
CPU 指令重新排序(假设我们谈论的是 x86 之类的东西)被设计为透明的;它应该对程序的逻辑结果没有影响。
-
据我了解,CPU 的工作通常是隐式添加无序执行所需的必要同步。通常,它会保持内存同一部分上的内存操作彼此同步,因此它的行为就像访问没有重新排序一样。
-
CPU 指令重新排序并不能保证程序的结果是相同的。考虑通过共享变量在多个线程之间进行通信,或访问外部设备。
标签: c compiler-construction assembly standards