- Momory Ordering
- 9.2.3.2 Neither Loads Nor Stores Are Reordered
- 9.2.3.3 Stores Are Not Reordered With Earlier Loads
- 9.2.3.4 Loads May Be Reordered with Earlier Stores (intel x64架构下唯一会有memory reorder的情况)
- 内存屏障的实现
参考:HPC(高性能计算第一篇):一文彻底搞懂并发编程与内存屏障 [1] [2] [3]
Momory Ordering
memory barrier是memory乱序后产生的问题,和cpu架构强相关。
参考:Intel sdm手册 卷3A 多处理器管理,第二小节:内存顺序,专门讲述Memory barrier问题;
9.2.3.2 Neither Loads Nor Stores Are Reordered
9.2.3.2 节,是第一个关于内存顺序的例子
Q: 何为乱序?
A:
-
- 两个操作独立,互不依赖,多流水线架构下两条指令可以同时执行;
-
- 同时执行或者先后执行的情况下,也可能因为_y变量已经存在于cache中而先于_x执行
-
- intel cpu架构下,虽然2)执行乱序,但是到最后阶段(提交阶段吗?)又会顺序退出,即旁观者看来还是_x先执行完_y再执行完,所以intel的sdm手册这一小节的标题为Neither loads nor strores are reoredered,并描述r1 = 1 and r2 = 0 is not allowed,CPU使用一个叫
内存排序区
的部件,完成这种顺序性(待研究
)
- intel cpu架构下,虽然2)执行乱序,但是到最后阶段(提交阶段吗?)又会顺序退出,即旁观者看来还是_x先执行完_y再执行完,所以intel的sdm手册这一小节的标题为Neither loads nor strores are reoredered,并描述r1 = 1 and r2 = 0 is not allowed,CPU使用一个叫
-
- 其他cpu架构,允许提交阶段乱序的话,那么P1就可能看到_y = 1 _x = 0的结果
Q: 对于4)怎么解决?
A:P0加上write_barrier, P1加上read_barrier(read同样可能乱序)
9.2.3.3 Stores Are Not Reordered With Earlier Loads
接下来的9.2.3.3 节描述了另外一种场景先有load操作再有store操作,这种场景下store操作也不会被reorder到load操作前
9.2.3.4 Loads May Be Reordered with Earlier Stores (intel x64架构下唯一会有memory reorder的情况)
9.2.3.4 读可以重排到写之前, intel x64架构下唯一会有memory reorder的情况
比如有种代码逻辑:1)mov _x,1 表示加本地的锁;2)mov r1, _y 表示检测其他线程当前是否有上锁;3)如果r1或者r2为0,表示其他线程没上锁,当前线程可以执行
正常顺序下,某一方赋值先执行,则另外一方读取肯定不为0,r1 r2可以是(1,1)(1,0)(0,1),但是同时为0不会发生,即P0 P1不会同时执行需要互斥的临界代码
有memory reorder下,read先于之前的write先执行,则r1 r2可能会同时为0,导致P0 P1同时执行需要互斥的临界代码
如果不想有这种乱序则需要上内存屏障
+++
内存屏障是内存顺序问题,即,内存操作本来是能分清先后顺序的,写先读后,但顺序被打乱了,读被提到前面了。如果不想打乱顺序,需要“屏障”,挡住后面的读,防止它提前执行、提前完成。
当程序逻辑依赖读写顺序,才需要使用内存屏障,如果程序逻辑并不依赖顺序,就让读被提前吧,这样对性能有帮助
(判断程序逻辑是否依赖顺序,有时候不是那么容易的)
内存屏障的实现
lock 和 mfence 指令