gcc - mfence 和 asm volatile 的区别 ("": : : "memory")

标签 gcc x86 memory-barriers

据我所知,mfence 是一个硬件内存屏障,而 asm volatile ("": : : "memory") 是一个编译器屏障。但是,可以使用 asm volatile ("": : : "memory") 来代替 mfence。

我感到困惑的原因是 this link

最佳答案

嗯,只有内存排序较弱的架构才需要内存屏障。 x86 和 x64 没有弱内存排序。在 x86/x64 上,所有存储都有释放栅栏,所有负载都有获取栅栏。所以,你应该只需要 asm volatile ("": : : "memory")

有关 Intel 和 AMD 的详细概述以及相关制造商规范的引用,请参阅 http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/

通常,像“ volatile ”这样的东西是在每个字段的基础上使用的,其中对该字段的加载和存储本身就是原子的。如果对字段的加载和存储已经是原子的(即,所讨论的“操作”是对单个字段的加载或存储,因此整个操作是原子的), volatile 字段修饰符或内存屏障x86/x64 上不需要。尽管有可移植代码。

当涉及到非原子的“操作”时——例如加载或存储到大于 native 单词的字段,或者加载或存储到“操作”内的多个字段——无论 CPU 如何,都需要一种可以将操作视为原子操作的方法建筑学。 通常这是通过诸如互斥体之类的同步原语来完成的。互斥体(我使用过的)包括内存屏障,以避免处理器重新排序等问题,因此您不必添加额外的内存屏障指令。我通常认为不使用同步原语是一种过早的优化;但是,过早优化的本质当然是 97% 的时间:)

如果您不使用同步原语并且正在处理多字段不变量,那么确保处理器不会对存储和加载到不同内存位置进行重新排序的内存屏障非常重要。

现在,不在 asm volatile 中发出“mfence”指令,而是在 clobber 列表中使用“内存”。据我所知read

If your assembler instructions access memory in an unpredictable fashion, add `memory' to the list of clobbered registers. This will cause GCC to not keep memory values cached in registers across the assembler instruction and not optimize stores or loads to that memory.

当他们说“GCC”并且没有提及任何有关 CPU 的内容时,这意味着它仅适用于编译器。缺少“mfence”意味着不存在CPU内存屏障。您可以通过反汇编生成的二进制文件来验证这一点。如果没有发出“mfence”指令(取决于目标平台),那么很明显 CPU 没有被告知发出内存围栏。

根据您所在的平台以及您想要做的事情,可能会有一些“更好”或更清晰的东西......但不考虑可移植性。

关于gcc - mfence 和 asm volatile 的区别 ("": : : "memory"),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12183311/

相关文章:

c++ - 编译 GCC 时错误部分模板特化,但不是 MSVC

c - 将数据与用户输入分开。

c++ - 编译应用程序时出现奇怪的错误

gcc - 如何测量处理器周期中的 x86 和 x86-64 汇编命令执行时间?

c - 一些由clang生成的程序集不能在实模式下工作(.COM,微小内存模型)

c - 如何从上下文中手动递增指令指针?

c++ - 具有 memory_order_relaxed 的存储是否有可能永远不会到达其他线程?

c - CPU乱序影响测试程序

c - 为什么进程之间没有切换

c++ - 在 C++ 中,加载是否可以在获取操作下方滑动/存储可以在释放上方 float 吗?