Lunarain_079's Inn

Back

内存屏障(Memory Barrier)通过限制指令重排序刷新缓存的方式,确保某些读写操作在 CPU 和缓存之间可见且按顺序生效。它是多核系统中保证内存可见性和有序性的重要工具。

1.多核 CPU 的内存一致性问题#

在多核系统中,每个 CPU 核心都有自己的缓存(L1/L2),读写内存时:

  • 可能只在本地缓存中操作,不会立刻刷新到主内存
  • 也可能从缓存读取旧值,看不到其他核心刚写的新值

因此,即使线程 A 修改了变量,线程 B 不一定能立刻看到这个修改

2.内存屏障的作用#

内存屏障(Memory Barrier,也叫 Memory Fence)有两个核心作用:

  1. 阻止指令重排序
  2. 控制缓存刷新/失效,以实现内存可见性

它是一种CPU 和编译器层面的指令(或者伪操作),保证某些操作在屏障前完成并对其他处理器可见

3.内存屏障的类型(以 ARM / x86 / Java 内存模型为例)#

类型含义作用
Load Barrier(读屏障)屏障后的读不能被重排到屏障前保证之后的读操作不会看到过早的值
Store Barrier(写屏障)屏障前的写不会被重排到屏障后保证之前的写操作对其他 CPU 可见
Full Barrier(全屏障)读写都不能重排读写顺序和可见性全都保证

4.多核同步中的场景:CPU 如何“看到”其他 CPU 的写入#

例如,CPU A 执行如下代码:

x = 1;               // 写共享变量
memory_barrier();    // 写屏障
flag = 1;            // 发布完成信号
c

CPU B 执行:

while (flag == 0);   // 等待信号
memory_barrier();    // 读屏障
print(x);            // 读取共享变量
c

如果没有 memory barrier,CPU B 可能会乱序执行 print(x)flag 检查之前,此时 x 还没更新,会打印出错误值。

内存屏障确保 CPU A 先完成 x 的写入、刷新缓存,再设置 flag;CPU B 等到 flag 后,再读取最新的 x。

5.它是如何实现“让别的 CPU 看到”的?#

具体机制依赖 CPU 架构,主要包括:

  1. 写缓冲刷新(Write Buffer Flush)
    • 屏障会强制将写缓冲中的数据写入主内存(可见于其他 CPU)
  2. 缓存一致性协议(如 MESI)
    • 其他 CPU 访问该地址时会检测缓存一致性,通过总线探测或点对点消息获取最新数据
  3. 缓存失效(Invalidate)或刷新(Flush)
    • 某些屏障指令会使本地缓存失效,从而迫使从主内存重新加载数据

6.Java 示例(用 volatile#

volatile int flag = 0;
int data = 0;

Thread A:
data = 42;
flag = 1;  // volatile 写,有 Store Barrier

Thread B:
if (flag == 1) {     // volatile 读,有 Load Barrier
   System.out.println(data); // 保证能看到最新的 data
}
java

这里的 volatile 编译后插入内存屏障,确保写入和读取都对其他线程可见。

内存屏障
https://www.lunarain.top/blog/%E5%86%85%E5%AD%98%E5%B1%8F%E9%9A%9C
Author Lunarain_079
Published at April 11, 2025
Comment seems to stuck. Try to refresh?✨