跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

内存屏障(Memory Barrier):详述 LoadLoad、StoreStore、LoadStore、StoreLoad 四种屏障的阻断逻辑

内存屏障是对特定访存操作施加顺序约束的指令,不禁止乱序执行本身,而是确保某类操作在另一类操作完成后才能开始;LoadLoad、StoreStore、LoadStore、StoreLoad 四种屏障分别约束读-读、写-写、读-写、写-读间的执行顺序,防止重排序引发可见性或依赖性错误。

内存屏障不是“拦住”所有指令,而是对特定类型访存操作之间施加顺序约束。它不禁止乱序执行本身,而是告诉 CPU:“某类操作必须在另一类操作完成之后才能开始”。四种屏障各自锁定不同组合的读(Load)和写(Store)行为,核心是防止因重排序导致的可见性或依赖性错误。

LoadLoad 屏障:读操作不能跨屏障提前它保证屏障前的所有读操作(如Load1)一定先于屏障后的读操作(如Load2)完成并返回结果。CPU 不会把 Load2 提前调度到 Load1 之前执行,也不会让 Load2 读到 Load1 还未生效的旧缓存副本。

典型场景:连续读取两个有依赖关系的变量,比如先读标志位再读数据硬件动作:阻塞后续 load 指令进入加载队列,直到前面所有 load 从 cache 或主存返回有效数据常见插入点:volatile 读之后、锁获取后第一个读操作前StoreStore 屏障:写操作不能跨屏障错序它确保屏障前的写(Store1)已提交到 store buffer 并对其他处理器可见(至少到达 L1 数据缓存),之后才允许屏障后的写(Store2)发起。否则 Store2 可能覆盖 Store1 尚未刷出的中间状态。

典型场景:先更新数据字段,再更新状态标志,避免其他线程看到“已就绪”但数据仍为空硬件动作:清空或同步 store buffer 中靠前的条目,防止 Store2 的地址/数据早于 Store1 到达一致性域常见插入点:volatile 写之前、锁释放前的最后一批写操作后LoadStore 屏障:读完才能写,防止读后写错乱它强制屏障前的读(Load1)必须完成并拿到结果后,屏障后的写(Store2)才能启动。这切断了“读-写”之间的非法重排,避免 Store2 基于过期或未完成的读结果进行修改。

典型场景:“检查后更新”模式,例如先读 count 再递增并写回硬件动作:延迟 store 指令发射,直到确认 Load1 的地址翻译、cache line 加载、数据返回全部完成常见插入点:volatile 读之后紧接着普通写、锁内读操作后紧接写操作StoreLoad 屏障:写完才准读,最强且开销最大它要求屏障前的写(Store1)对所有处理器完全可见(store buffer 刷空、缓存行失效确认完成)后,屏障后的读(Load2)才能开始。这是唯一能同时阻止 Store-Load、Load-Load、Store-Store 和 Load-Store 重排的屏障,在 x86 上常由mfence实现。

典型场景:volatile 写后立刻读另一个 volatile 变量、锁释放后马上读共享状态硬件动作:等待所有 pending store 刷入 cache/coherence domain;同步 invalidation queue;部分架构还隐式序列化整个 store buffer注意:JVM 在每个 volatile 写后自动插入此屏障,也是 synchronized 释放锁时的隐含保障

相关文章