我发现x86 CPU有以下内存屏障指令:mfence
,lfence
和sfence
。
x86 CPU是否只有这三个内存屏障指令,还是有更多?
sfence
(SSE1)和mfence
/ lfence
(SSE2)是唯一以其内存栅栏/屏障功能命名的指令。除非您使用NT加载或存储和/或WC内存,否则只需要mfence
进行内存排序。
(请注意,英特尔CPU上的lfence
也是乱序执行的障碍,所以它可以序列化rdtsc
,对于幽灵缓解有用,可以防止推测性执行。在AMD上,必须设置一个MSR,否则lfence
基本上是nop
(4 /周期吞吐量)。该MSR是通过Spectre-mitigation微码更新引入的,通常由更新的内核设置。)
像lock
这样的lock add [mem], eax
ed指令也是完全的记忆障碍。 Does lock xchg have the same behavior as mfence?。 (虽然可能不像mfence
那样强大,可以从WC内存中订购NT负载:Do locked instructions provide a barrier between weakly-ordered accesses?)。 xchg [mem], reg
有一个隐含的lock
前缀,因此它也是一个障碍。
In my testing on Skylake,lock
ed指令阻止使用此代码https://godbolt.org/g/7Q9xgz对常规商店的NT商店进行重新排序。
xchg
似乎是一个做seq-cst商店的好方法,特别是在像Skylake这样的英特尔硬件上,mfence
也阻止了纯ALU指令的无序执行,比如lfence
:请参阅the bottom of this answer。
AMD还建议使用xchg
或其他锁定指令代替mfence
。 (mfence
在AMD手册中记录为序列化AMD,所以它总是会受到阻止OoO exec的惩罚)。
对于没有SSE的32位目标上的顺序一致性存储或完全障碍,编译器通常仅使用lock or [esp], 0
或其他无操作锁定指令来实现内存屏障效果。 That's what g++7.3 -O3 -m32 -mno-sse
does为std::atomic_thread_fence(std::memory_order_seq_cst);
。
但无论如何,无论某些CPU的实现细节如何,mfence
和lock
ed insns在架构上都没有被定义为在英特尔上进行序列化。
像cpuid
这样的完整序列化指令也是完整的内存屏障,耗尽了存储缓冲区以及刷新管道。 Does lock xchg have the same behavior as mfence?有英特尔手册的相关引用。
在Intel处理器上,以下是体系结构序列化指令(来自:https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol3/o_fe12b1e2a880e0ce-273.html):
MOV CR8
没有序列化。 WRMSR
到IA32_TSC_DEADLINE MSR(MSR索引6E0H)和X2APIC MSR(MSR索引802H到83FH)没有序列化。在AMD处理器上,以下是体系结构序列化指令:
英特尔处理器上的术语“[完全]序列化指令”与AMD处理器完全相同,只有一个区别:来自CLFLUSH
(但不是CLFLUSHOPT
)的缓存行刷新操作是针对后来的指令排序的,只有QQ上的MFENCE
处理器。
in
/ out
(及其字符串复制版本ins
和outs
)是完整的记忆障碍,也是部分序列化(如lfence
)。文档说它们延迟执行下一条指令,直到I / O事务的“数据阶段”之后。
脚注:
(1)根据BJ137(Sandy Bridge),HSD152(Haswell),BDM103(Broadwell):
问题:通过从嵌套任务返回导致任务切换的IRET指令不会序列化处理器(与软件开发人员手册第3卷标题为“序列化指令”相反)。
含义:在任务切换期间依赖于IRET的序列化属性的软件可能无法按预期运行。英特尔没有观察到此错误影响任何商用软件的运行。
解决方法:未确定。如果需要序列化,软件可以在IRET指令之前立即执行MFENCE指令。
你是对的,x86 CPU上唯一的三个内存屏障功能是:
LFENCE
SFENCE
MFENCE