内存屏障,简称MB,名字够龌龊。

参考wikipedia的定义:
      Memory barrier, also known as membar or memory fence or fence instruction, is a type of barrier and a class of instruction which causes a central processing unit (CPU) or compiler to enforce an ordering constraint on memory operations issued before and after the barrier instruction.

内存屏障机制可以用来解决很多问题。


一、解决多核Cache问题

当代计算机系统架构中有Cache的概念,而Cache会引入一些问题。内存屏障就是解决这些问题的一个方法。
强烈推荐看《Memory Barriers: a Hardware View for Software Hackers》

内存屏障(Memory Barriers)-LMLPHP


先来个简单的例子,做多核CPU系统上,运行程序:

有全局变量a,b 它们都被初始化为 0

Processor #0:
  1. void foo(void)
  2. {
  3.    a = 1;
  4.    b = 1;
  5. }
Processor #1:
  1. void bar(void)
  2. {
  3.    while(b == 0) continue;
  4.    printk("%d\n",a);
  5. }

上面的例子中,期望输出“1”,但结果并不总是这样,有时会输出"0"。
一个可能的序列是这样:

a在CPU_1的cache里
b在CPU_0的cache里

1. CPU_0 执行 a = 1,
   为了完成对a的写操作,CPU_0 把value“1”放到buffer中,同时给CPU_1发送“read invalidate”,告诉别人a不能读,我要改它
2. CPU_1 执行 while(b==0) continue; 
   为了完成对b的读操作,CPU_1 发出"read"给其他CPU,告诉别人,别改b,我要读它
3. CPU_0 执行 b = 1
   b在CPU_0的cache里,直接更新b在cache里的值

4. CPU_0 接收到了CPU_2的“read”
   CPU_0把“b”在Cache里的值share给CPU_1

5. CPU_1 接收到“b”的share,把“b”放在自己的cache中

6. CPU_1 执行while(b==0) continue;
   再次去cache里拿“b”的值,为1, 从while循环中跳出

7. CPU_1 执行printk("%d\n",a);
   对a执行读取操作,一看a在cache里,为0,拿出来,输出“0”

8. CPU_1 收到 CPU_0 的“read invalidate”信息,把对“a”的cache控制权给CPU_0。
   此时太晚了,CPU_1已经使用了“a”的旧值

9. CPU_0接收到 “a”的cache控制权,更新其值为“1”
   
使用内存屏障,可以解决上述问题
Processor #2:
  1. a = 22;
  2. smp_mb();
  3. b = 1;
二、解决gcc编译优化导致的问题

三、解决多核同步问题

四、API
五、不同架构上的实现
09-21 07:12