首先我们考虑下面的这个场景(假设所有变量的初始值都为0):大多数程序员都预期内核C2的寄存器r2应该得到值NEW。
C2的寄存器r2一定能得到NEW么?
然而,在如今的很多计算机体系结构中,r2可以是0。因为硬件可以通过reorder内核C1的store S1和S2来使r2得到值0,毕竟这个S1和S2访问的是不同的地址。
一个可能的执行情况:
注:这里的“内核”指的是不同的线程(context),不管是不是同一个内核。
下面给出一些处理器核心可能会reorder的一些情况:
在大多数情况下,我处理器核心都会保证对同一个地址空间内存访问的顺序,并可能reorder对不同地址的内存访问。
根据内存访问的类型(load和store),我们可以将可能的reorder分为三种情况。
Store-store reorder
1、如果一个处理器内核有一个非first-in-firstout write buffer,也就是说允许store以不同于它们写入的顺序从write buffer离开,那么对不同地址的store-store可能会reorder。
2、第一个store miss,而第二个store hit会发生这种情况
3、如果第二个 store与第一个store之前的某个store访问合并了,也会发生这种情况。
这种store-store reorder对于单线程没有功能影响,然而对于上表中的场景(CoreC1的S1指令和S2指令发生store-store order),会导致Core C2拿到了SET之前的data值0。
Load-load reorder
现代处理器核心都是动态调度的,也就是说程序实际在处理器中指令执行顺序和程序编写的顺序可能是不一致的。例如在上述示例中, CoreC2可以乱序执行 L1和L2。同样,如果只考虑单线程,这种对于不同的地址发生load-load reorder也是没有功能问题的。但是,考虑到多线程,这种load-load乱序会导致CoreC2中的寄存器r2拿到值0(这可能是程序员不期望的。)。
Load-store 和 store-load reorder
乱序核心同样也可能会对load-store和store-load进行reorder。
r1和r2能够同时拿到值0么?
一般情况下,程序是不会让寄存器r1和寄存器r2同时拿到值0的,但是由于CoreC1 reorder S1和L1,CoreC2 reorderS2和L2,导致寄存器r1和寄存器r2同时拿到值0这种违反直觉的结果。
所以,正是因为存在上述问题,程序的执行存在了不确定性(允许有多个结果),才需要 内存一致性模型 ,程序员、编译器和硬件设计人员需要明确一个共识,知道硬件和软件分别应该提供什么以及保证什么?
原作者:验证哥布林
|