【问题标题】:Does volatile act as a compiler barrier for optimizationvolatile 是否充当优化的编译器屏障
【发布时间】:2017-10-01 23:09:47
【问题描述】:

是否允许编译器通过将语句(不是表达式的一部分)从 volatile 访问之前移动到之后,或者从 volatile 访问之后移动到它之前来优化代码流。

参考我对SO : is volatile required for synchronous ISR access的回答

对我的回答的异议表明,使用 volatile 不会导致 C++(和 C)的通用机器确保完成之前的所有操作。

我对@9​​87654322@的阅读

也就是说,在单个执行线程中,易失性访问不能被优化或重新排序,而另一种可见的副作用是在易失性访问之前排序或在易失性访问之后排序。这使得 volatile 对象适合与信号处理程序通信,但不适用于另一个执行线程

对于我的回答中的情况是否如此 - 单核操作以下应该是正确的。

  • 结果尽可能快地可见 - 可能在某个点上对 volatile 的更改尚未写入,但如果已写入,则单核将在信号处理程序中看到它,(或ISR)。
  • 兼容的 C++ 编译器无法围绕 volatile 写入重新排序操作,因为它是一种可见的副作用。

我在这个线程上的回答假设特定情况是单核 CPU,并且 C++11 不适用,所以我希望在该范围内得到答案。

【问题讨论】:

  • 编译器可以重新排序所有内容,只要按程序顺序发生有序的可观察副作用(包括易失性访问) - 请参阅 [intro.execution]
  • @Cubbi 几乎没有人真正理解这样说的标准。例如,大多数 x86 编译器允许对 volatile 写入重新排序。 (查看生成的程序集,不会有内存屏障。所以写入可以按任意顺序进行。)
  • @DavidSchwartz x86 编译器正在正确地完成他们的工作,并将易失性访问视为可观察到的副作用。
  • @Cubbi 同意。但它们不能确保它们按程序顺序发生。这样做需要内存屏障,而编译器不会产生它们。它们允许写入以任何顺序发生,即使它们将它们视为可观察到的副作用。
  • @DavidSchwartz 为什么你期望有障碍?如果在这里什么都不做。没有线程间同步。 (更多关于主题,也没有编译器障碍 - 因为 OP 需要 std::atomic_signal_fence)

标签: c++ language-lawyer


【解决方案1】:

C++ 标准不区分代码流所说的和代码所做的。所以这个问题,以及所有关于代码流而不是可观察行为的问题,都是一个特定于平台的问题。

兼容的 C++ 编译器无法围绕 volatile 写入重新排序操作,因为它是一种可见的副作用。

没有人理解这样说的标准。这就是 x86 编译器volatile 操作周围设置内存屏障并允许 CPU 重新排序的原因。

【讨论】:

  • 内存屏障与多核行为有关。我在询问单核机器的行为,以及编译器是否可以重新排序 a =f(x); b = g(y);当变量之一 (a,b,x,y) 是 volatile 时。
  • 您似乎回答了与我不同的问题。我问编译器是否可以重新排序语句。您的声明谈到了 CPU 是否可以重新排序指令。我接受 CPU 能够重新排序指令,但前提是它得到正确的结果。
  • @mksteve 内存屏障与多核行为有关,当然,但它也与单核行为有关。例如,两次写入之间的内存屏障可确保这两次写入实际上是按顺序进行的。 (并且“作为可见的副作用”也是特定于平台的,因为没有平台中立的写入可见性概念。)
  • @mksteve 正如我所说,这是特定于平台的。 C++ 标准不区分编译器可以做什么和 CPU 可以做什么。怎么可能?它只说明必须发生的事情,而不关心哪些组件完成了它或它们是如何做到的。 编译器 能做什么,与 CPU 能做什么不同,是一个平台和实现特定的问题。最终结果必须遵循标准,但实现该结果的部分有什么责任是特定于平台的。
猜你喜欢
  • 2018-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多