FILE TAG
misc
START
Basic
什么是内存序?什么是乱序执行?
Back:
首先一个前提:编译器会对源代码做编译优化,调整代码执行的顺序,所以送到 CPU 的程序就已经不是保持程序序的了。
乱序处理器会:
- 指令队列中等待的数据一旦操作数就绪就送入功能单元中执行
- 执行得到的结果会写入
Store Buffer
,而不是直接写入 Cache - 只有更早请求执行的指令结果写入cache后,指令执行结果才写入Cache,通过对指令结果排序写入cache,使得执行看起来是有序的
Store Buffer
是保证如果 cache miss 了,指令不会等待 Cache 就绪(从内存中读取),而是送入 Store Buffer
中并告知 core 已完成,当随后 Cache 就位的时候 Store Buffer
才自动写入对应 Cache。
Stroe Buffer
会存在读到旧值的问题,因此有Store Buffer Forwarding 技术来判断 Buffer 里是否有悬而未决的新值,有了这个保证,单核的执行就能遵从程序顺序性了。
虽然对一个Core而言,如上所述,这个Core观察到的内存操作顺序不一定符合程序序,但内存操作序和程序序必定产生相同的结果,如果单核上乱序执行会影响结果,那编译器的指令重排和CPU乱序执行便不会发生,硬件会提供这项保证。
但多核系统,硬件不提供这样的保证,多线程程序中,每个线程所工作的Core观察到的不同内存操作序,以及这些顺序与全局内存序的差异,常常导致多线程同步失败,所以,需要有同步机制确保内存序与程序序的一致,内存屏障(Memory Barrier)的引入,就是为了解决这个问题,它让不同的Core之间,以及Core与全局内存序达成一致。
END
START
Basic
什么是内存屏障?
Back:
当一个变量加载到多个core的Cache,则这个Cache Line处于Shared状态,如果Core1要修改这个变量,则需要通过发送核间消息Invalidate来通知其他Core把对应的Cache Line置为Invalid。
实际上,invalid 这个动作也是 buffer 的,否则会存在一个写 core 要等待很多其他 core 的情况。这样进一步加大了读到旧值的可能性
内存屏障(Memory Barrier),也称内存栅栏、屏障指令等,是一类同步屏障指令,是CPU或编译器在对内存随机访问的操作中的一个同步点,同步点之前的所有读写操作都执行后,才可以开始执行此点之后的操作。语义上,内存屏障之前的所有写操作都要写入内存;内存屏障之后的读操作都可以获得同步屏障之前的写操作的结果。
- 写屏障wmb保障了barrier前后操作的顺序,它不关心barrier前的多个操作的内存序,以及barrier后的多个操作的内存序,是否与Global Memory Order一致。可以解决 Store Buffer 中的副本问题
- 读屏障 rmb 类似,可以解决 Invalidate Buffer 中的副本导致的不一致读问题。
END