【问题标题】:Do C90-compliant compilers have to take into account instruction reordering by the CPU?兼容 C90 的编译器是否必须考虑 CPU 的指令重新排序?
【发布时间】: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


【解决方案1】:

CPU 可能会重新排序指令,但它们必须确保结果与没有时相同

【讨论】:

  • 并且 CPU 重新排序约束比通常的 C 标准“as-if”规则严格得多,因为即使是真实处理器的状态也必须保持“好像”重新排序没有发生。
  • @HermannSpeiche:如果您唯一的线程安全形式是使用volatile,那么即使没有 CPU 指令重新排序,您也会遇到问题。您应该使用正确的线程同步机制。
  • @Hermann:C 标准准确地说明了您在问题中所说的内容; volatile 只是关于序列点的保证。 C 标准没有线程的概念:在单线程环境中,CPU 重新排序没有影响;在多线程环境中,我们超出了标准的范围......
  • @OliCharlesworth:“C 标准没有线程的概念”——现在有了。最近批准的 ISO C11 标准包括(可选)线程支持。
  • @drhirsch:不,那是 C。今年 C 和 C++ 都有新的 ISO 标准。 open-std.org/JTC1/SC22/WG14, iso.org/iso/iso_catalogue/catalogue_tc/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-23
  • 1970-01-01
  • 2021-03-30
  • 2016-12-27
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多