C ++ volatile关键字是否引入了内存围栏?
我明白volatile
告诉编译器该值可能会改变,但为了完成这个功能,编译器是否需要引入一个内存栏来使其工作?
根据我的理解,对易失性对象的操作顺序不能重新排序并且必须保留。 这似乎意味着一些记忆栅栏是必要的,并且没有真正解决这个问题的方法。 我说得对吗?
在这个相关的问题上有一个有趣的讨论
乔纳森Wakely写道:
......只要它们出现在单独的完整表达式中,对编译器的访问就不能被编译器重新排序...正确的说,volatile对于线程安全来说是无用的,但并非出于他给出的原因。 这不是因为编译器可能会重新访问易失性对象,而是因为CPU可能会对它们进行重新排序。 原子操作和内存屏障阻止了编译器和CPU重新排序
David Schwartz在评论中回复:
......从C ++标准的角度来看,编译器在做某些事情和编译器发出指令,导致硬件做某事之间没有区别。 如果CPU可以重新排序对挥发性物质的访问,那么标准并不要求保留它们的顺序。 ...
... C ++标准对重新排序的内容没有任何区别。 而且你不能争辩说CPU可以对它们重新排序而没有可观察到的效果,所以没关系--C ++标准将它们的顺序定义为可观察的。 如果编译器生成的代码使平台符合标准要求,则编译器在平台上符合C ++标准。 如果标准要求访问挥发性物质不被重新排序,那么重新排序它们的平台不符合标准。 ...
我的观点是,如果C ++标准禁止编译器重新排序访问不同的挥发性物质,理论上这种访问的顺序是程序可观察行为的一部分,那么它还要求编译器发出禁止CPU执行的代码所以。 该标准没有区分编译器的功能和编译器的生成代码使CPU执行的操作。
这确实会产生两个问题:他们中的任何一个都是“正确的”? 实际的实现真的在做什么?
不要解释什么是volatile
,请允许我解释何时应该使用volatile
。
volatile
变量几乎是该标准允许您在信号处理程序中执行的唯一操作。 由于C ++ 11,你可以使用std::atomic
来达到这个目的,但是只有当原子是无锁的。 setjmp
。 例如:
volatile int *foo = some_memory_mapped_device;
while (*foo)
; // wait until *foo turns false
如果没有volatile
说明符,编译器可以完全优化循环。 volatile
说明符告诉编译器它可能不会假设2个后续读取返回相同的值。
请注意, volatile
与线程无关。 如果有不同的线程写入*foo
因为没有涉及获取操作,上述示例不起作用。
在所有其他情况下, volatile
使用应该被认为是不可移植的,除了处理pre-C ++ 11编译器和编译器扩展(如msvc的/volatile:ms
开关,它在默认情况下启用X86 / I64)。
C ++ volatile关键字是否引入了内存围栏?
不需要符合规范的C ++编译器引入内存围栏。 你的特定编译器可能; 将你的问题引导至编译器的作者。
C ++中的“volatile”函数与线程无关。 请记住,“易失性”的目的是禁用编译器优化,以便从由于外部条件而改变的寄存器读取数据不会被优化。 是由另一个CPU上的另一个线程写入的内存地址是否由于外部条件而发生更改? 不需要。如果一些编译器作者选择处理由不同CPU上的不同线程写入的内存地址,就好像它们是由于外部条件导致的寄存器更改一样,那就是他们的业务; 他们不需要这样做。 例如,它们也不需要(即使它引入了内存围栏)来确保每个线程都看到易失性读写的一致排序。
实际上,volatile在C / C ++线程中几乎没有用处。 最佳做法是避免它。
此外:内存隔离是特定处理器体系结构的实现细节。 在C#中,显式设计用于多线程的volatile,该规范并没有说将引入半围墙,因为该程序可能运行在首先没有围墙的体系结构上。 相反,规范对编译器,运行时和CPU放弃某些(非常弱)约束条件来限制某些副作用的排序做了某些(非常弱)的保证。 在实践中,这些优化通过使用半围栏来消除,但这是未来可能会改变的实现细节。
事实上,你关心任何语言中volatile的语义,因为它们与多线程有关,这表明你正在考虑跨线程共享内存。 考虑不要这样做。 它使你的程序难以理解,并且更容易包含微妙的,不可能再现的错误。
David所忽略的是c ++标准规定了几个线程只在特定情况下进行交互的行为,而其他所有情况都会导致未定义的行为。 如果不使用原子变量,至少包含一次写入的竞态条件是未定义的。
因此,编译器完全有权放弃任何同步指令,因为您的cpu只会注意到由于缺少同步而显示未定义行为的程序中的差异。
链接地址: http://www.djcxy.com/p/30719.html上一篇: Does the C++ volatile keyword introduce a memory fence?
下一篇: Fences in C++0x, guarantees just on atomics or memory in general