sfence
(上交所1)和mfence
/ lfence
(SSE2) 是唯一以其内存栅栏/屏障功能命名的指令。除非您使用 NT 存储和/或 WC 内存(以及 NT 从 WC 加载),否则仅mfence
内存排序需要。
(注意lfence在Intel CPU上也是乱序执行的障碍,因此它可以序列化rdtsc
,并且对于 Spectre 缓解很有用,可以防止推测执行。在AMD上,必须设置MSR,否则lfence
基本上是一个nop
(4/周期吞吐量)。该 MSR 是通过 Spectre 缓解微代码更新引入的,通常由更新的内核设置。)
lock
ed 指令如lock add [mem], eax
也是满内存屏障. lock xchg 与 mfence 具有相同的行为吗?。 (虽然可能不如mfence
用于从 WC 内存订购 NT 加载:锁定指令是否在弱顺序访问之间提供了屏障?). xchg [mem], reg
有一个隐含的lock
前缀,所以它也是一个障碍。
在我对 Skylake 的测试中, lock
ed 指令会使用此代码阻止 NT 存储与常规存储的重新排序https://godbolt.org/g/7Q9xgz.
xchg
似乎是进行 seq-cst 存储的好方法,特别是在 Intel 硬件上,例如天湖在哪里mfence
还阻止纯 ALU 指令的乱序执行, like lfence
: See 这个答案的底部.
AMD 还建议使用xchg
或其他锁定指令代替mfence
. (mfence
在 AMD 手册中记录为在 AND 上进行序列化,因此它总是会受到阻塞 OoO exec 的惩罚)。
对于没有 SSE 的 32 位目标上的顺序一致性存储或完全屏障,编译器通常使用lock or [esp], 0
或其他无操作锁定指令just为了记忆屏障效应。就是这样g++7.3 -O3 -m32 -mno-sse does为了std::atomic_thread_fence(std::memory_order_seq_cst);
.
但无论如何,都没有mfence
nor lock
ed ins 是建筑上的定义为 Intel 上的序列化,无论某些 CPU 上的实现细节如何。
完整的序列化指令,例如cpuid
也是满内存屏障,排空存储缓冲区并刷新管道。lock xchg 与 mfence 具有相同的行为吗?Intel手册中有相关引用。
在 Intel 处理器上,以下是架构序列化指令(来自:https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol3/o_fe12b1e2a880e0ce-273.html):
-
特权序列化指令— INVD、INVEPT、INVLPG、INVVPID、LGDT、LIDT、LLDT、LTR、MOV 到控制寄存器、MOV(到调试寄存器)、WBINVD 和 WRMSR。
例外情况:MOV CR8
没有序列化。WRMSR
IA32_TSC_DEADLINE MSR(MSR 索引 6E0H)和 X2APIC MSR(MSR 索引 802H 到 83FH)未序列化。
-
Non-privileged serializing instructions — CPUID, IRET1, and RSM
在 AMD 处理器上,以下是架构上的序列化指令:
Intel 处理器上的术语“[完全]序列化指令”与 AMD 处理器上的含义完全相同,除了一个区别:高速缓存行刷新操作CLFLUSH
(但不是CLFLUSHOPT
)仅针对后续指令进行排序MFENCE
在 AMD 处理器上。
in
/ out(以及它们的字符串复制版本ins
and outs)是完整的内存屏障,并且也是部分序列化(例如lfence
)。文档称,它们会延迟执行下一条指令,直到 I/O 事务的“数据阶段”之后。
脚注:
(1) 根据BJ137(Sandy Bridge)、HSD152(Haswell)、BDM103(Broadwell):
问题:IRET 指令导致任务切换
从嵌套任务返回不会序列化处理器
(与软件开发人员手册第 3 卷标题为
“序列化说明”)。
含义:依赖序列化的软件
任务切换期间 IRET 的属性可能不会表现为
预期的。英特尔尚未发现此错误会影响
任何商业软件的操作。
解决方法:未确定。软件可以执行 MFENCE
如果序列化,则紧接在 IRET 指令之前的指令
是需要的。