从硬件引申出内存屏障,带你深入了解Linux内核RCU
17.CPU 1现在能够装载"b"的值了,由于它发现"b"的值为1,它退出while循环并执行下一条语句。
18.CPU 1执行assert(a== 1),但是包含"a"的缓存行不在它的缓存中。一旦它从CPU0获得这个缓存行,它将使用最新的"a"的值,因此断言语句将通过。
正如你看到的那样,这个过程涉及不少工作。即使某些事情从直觉上看是简单的操作,就像"加载a的值"这样的操作,都会包含大量复杂的步骤。
前面提到的,其实是写端的屏障,它解决Write buffer引入的内存乱序。接下来我们看看读端的屏障,它解决使无效队列引入的内存乱序。
要避免使无效队列例子中的错误,应当再使用读端内存屏障:
读端内存屏障指令能够与使无效队列交互,这样,当一个特定的CPU执行一个内存屏障时,它标记无效队列中的所有条目,并强制所有后续的装载操作进行等待,直到所有标记的条目都保存到CPU的Cache中。因此,我们可以在bar函数中添加一个内存屏障,如下:
1 void foo(void)
2 {
3 a = 1;
4 smp_mb();
5 b = 1;
6 }
7
8 void bar(void)
9 {
10 while (b == 0) continue;
11 smp_mb();
12 assert(a == 1);
13 }
有了这个变化后,操作顺序可能如下:
1.CPU 0执行a= 1。相应的缓存行在CPU0的缓存中是只读的,因此CPU0将"a"的新值放入它的存储缓冲区,并且发送一个"使无效"消息以刷新CPU1相应的缓存行。
2.CPU 1 执行while(b == 0) continue,但是包含"b"的缓存行不在它的缓存中,因此它发送一个"读"消息。
3.CPU 1 接收到 CPU 0的"使无效"消息,将它排队,并立即响应它。
4.CPU 0 接收到CPU1的响应,因此它放心的通过第4行的smp_mb()语句,将"a"从它的存储缓冲区移到缓存行。
5.CPU 0 执行b= 1。它已经拥有该缓存行(换句话说, 缓存行已经处于"modified"或者"exclusive"状态),因此它存储"b"的新值到缓存行。
6.CPU 0 接收到"读"消息,并且发送包含新的"b"值的缓存行给CPU1,同时在自己的缓存中,标记缓存行为"shared"状态。
7.CPU 1 接收到包含"b"的缓存行并更新到它的缓存中。
8.CPU 1 现在结束执行while (b == 0) continue,因为它发现"b"的值为 1,它处理下一条语句,这是一条内存屏障指令。
9.CPU 1 必须停顿,直到它处理完使无效队列中的所有消息。
10.CPU 1 处理已经入队的"使无效"消息,从它的缓存中使无效包含"a"的缓存行。
11.CPU 1 执行assert(a== 1),由于包含"a"的缓存行已经不在它的缓存中,它发送一个"读"消息。
12.CPU 0 以包含新的"a"值的缓存行响应该"读"消息。
13.CPU 1 接收到该缓存行,它包含新的"a"的值1,因此断言不会被触发。
即使有很多MESI消息传递,CPU最终都会正确的应答。这一节阐述了CPU设计者为什么必须格外小心地处理它们的缓存一致性优化操作。
但是,这里真的需要一个读端内存屏障么?在assert()之前,不是有个循环么?
难道在循环结束之前,会执行assert(a == 1)?
对此有疑问的读者,您需要补充一点关于猜测(冒险)执行的背景知识!可以找CPU参考手册看看。简单的说,在循环的时候,a== 1这个比较条件,有可能会被CPU预先加载a的值到流水线中。临时结果不会被保存到Cache或者Write buffer中,而是在CPU流水线中的临时结果寄存器中暂存起来 。
这是不是非常的反直觉?然而事实就是如此。
对CPU世界中反直觉的东西有兴趣的朋友,甚至可以看看量子力学方面的书,量子计算机真的需要懂量子力学。让《深入理解并行编程》一书中提到的"薛定谔的猫"来烧一下脑,这只猫已经折磨了无数天才的大脑。除了霍金,还有爱因斯坦的大脑!
五、关于内存屏障进一步的思考
本文仅仅从硬件的角度,引申出内存屏障。其目的是为了后续文章中,更好的讲解RCU。因此,并不会对内存屏障进行深入的剖析。但是,对于理解RCU来说,本文中的内存屏障知识已经可以了。
更深入的思考包括:
1、读屏障、写屏障、读依赖屏障的概念
2、各个体系架构中,屏障的实现、及其微妙的差别
3、深入思考内存屏障是否是必须的,有没有可能通过修改硬件,让屏障不再有用?
4、内存屏障的传递性,这是Linux系统中比较微妙而难于理解的概念。
5、单核架构中的屏障,是为了解决什么问题?怎么使用?
6、屏障在内核同步原语中的使用,
- 工控机在IC卡加油工程中的应用(05-13)
- 联网汽车为什么选择Linux开源平台?(07-10)
- 多网络和Linux代理的Android无线远程控制系统(02-02)
- 基于嵌入式Linux的家居监控系统设计(02-22)
- 基于嵌入式Linux系统的导航软件设计思路(03-17)
- 新型嵌入式机器视觉系统的设计研究(04-21)