1. x86 TSO 的 store buffer 允许哪些重排,mfence、lock 前缀与编译器屏障分别约束什么?
x86 TSO 的 store buffer 允许哪些重排?mfence、lock 前缀与编译器屏障分别约束什么?
- TSO 重排:允许 store-load 重排(读越过较早的写),store-store/load-load 有序
- mfence:CPU 级全屏障(序列化 store/load),lock 前缀(原子指令)隐含全屏障
- 编译器屏障(asm volatile("":::"memory")):约束编译器不重排,不约束 CPU
x86 采用 TSO(Total Store Order):写操作先进入 store buffer(延迟可见),读操作可能越过"较早已发出的写"(读到旧值——store-load 重排);但 store-store(写按程序序)、load-load(读按程序序)、load-store(读不越过之后的写)都不重排,且不进行"写-写乱序提交"(TSO 得名:存在一个总存储序)。因此 x86 上唯一的硬件重排是"读越过更早的写"(经典 Dekker/DCL 类场景需屏障)。对应地:C++ 的 acquire/release 在 x86 上几乎免费(编译器屏障即可,因硬件已满足除 store-load 外的序);seq_cst store 需要额外处理(store-load 重排会破坏 SC,需 mfence 或 lock xchg)。
屏障分层:一、mfence——CPU 级全屏障:序列化所有内存操作(其前的 store/load 在 mfence 后可见/完成),是"硬件指令",影响其他核观察顺序(配合 SFENCE/LFENCE 细分写/读);二、lock 前缀(lock add/cmpxchg/xchg 等)——原子 RMW 指令,隐含完整屏障(该指令前的内存操作不得重排到其后、后不得重排到其前),x86 上"原子操作=屏障"(除 relaxed 语义的显式 nofence 变体如 movnti);三、编译器屏障(asm volatile("" ::: "memory") 或 atomic_signal_fence 相关)——只阻止编译器重排/缓存/消除该点前后的内存访问(保证"生成的机器码顺序"),不产生任何 CPU 指令、不影响 CPU 乱序/缓冲行为(CPU 仍可能按硬件规则重排)。三层关系:编译器屏障是"代码级"约束,mfence/lock 是"指令级"约束;写并发代码通常组合使用(编译器屏障 + 硬件屏障或原子指令)。工程:性能敏感代码在 x86 用 acquire/release(编译期屏障),seq_cst store 用 xchg 或 mfence;弱序平台(ARM)需 dmb/ldar 指令——同一 C++ 源码跨平台由编译器映射(x86 上 acquire 不生成指令、ARM 上生成屏障)。
先明确 TSO 唯一硬件重排(store-load)及其来源(store buffer),再分层讲 mfence/lock/编译器屏障的约束对象与 x86 上的映射差异。