Met*_*est 10 c cpu x86 memory-fences memory-barriers
我知道现代CPU可以无序执行,但是他们总是按顺序退出结果,如维基百科所述.
"Out of Oder处理器及时填写这些"插槽"并准备好其他指令,然后在结尾处重新排序结果,使其看起来正常处理指令. "
现在,当使用多核平台时,据说需要内存防护,因为由于乱序执行,可以在此处打印错误的x值.
Processor #1:
while f == 0
;
print x; // x might not be 42 here
Processor #2:
x = 42;
// Memory fence required here
f = 1
Run Code Online (Sandbox Code Playgroud)
现在我的问题是,由于乱序处理器(我假设MultiCore处理器的情况下的核心)总是按顺序退出结果,那么内存栅栏的必要性是什么.难道多核处理器的核心不会看到仅从其他核心退役的结果,或者它们是否也会看到正在进行中的结果?
我的意思是在我上面给出的例子中,当处理器2最终退出结果时,x的结果应该在f之前,对吗?我知道在乱序执行期间它可能在x之前修改了f,但它必须在x之前没有退役,对吗?
现在有了按顺序退出结果和缓存一致性机制,为什么你需要在x86中使用内存栅栏?
jan*_*neb 15
本教程解释了这些问题:http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-95-7.pdf
FWIW,在现代x86处理器上发生内存排序问题,原因是虽然x86内存一致性模型提供了非常强的一致性,但是需要明确的障碍来处理读写后一致性.这是由于称为"存储缓冲区"的东西.
也就是说,x86是顺序一致的(很好且易于推理),除了可以在早期存储中重新排序负载.也就是说,如果处理器执行序列
store x
load y
Run Code Online (Sandbox Code Playgroud)
然后在处理器总线上,这可能被视为
load y
store x
Run Code Online (Sandbox Code Playgroud)
这种行为的原因是上面提到的存储缓冲区,它是一个小的缓冲区,用于在它们出系统总线之前进行写入.负载延迟是OTOH,是性能的关键问题,因此允许负载"跳过队列".
请参阅http://download.intel.com/design/processor/manuals/253668.pdf中的第8.2节
内存栅栏确保所有其他内核都可以看到围栅内变量的所有更改,以便所有内核都具有最新的数据视图.
如果你没有放置内存,那么内核可能正在处理错误的数据,特别是在场景中可以看到这种情况,其中多个内核将处理相同的数据集.在这种情况下,您可以确保在CPU 0执行某些操作时,对数据集所做的所有更改现在对所有其他内核可见,然后可以使用最新信息.
一些架构,包括无处不在的x86/x64,提供了几个内存屏障指令,包括有时称为"全栅栏"的指令.完整的栅栏确保栅栏之前的所有装载和存储操作都将在栅栏后发出的任何装载和存储之前提交.
如果核心开始使用数据集上过时的数据,它怎么能得到正确的结果呢?如果最终结果是否以正确的顺序完成,则无论如何都是如此.
密钥位于缓存和CPU之间的存储缓冲区中,并执行以下操作:
存储缓冲区对远程CPU不可见
存储缓冲区允许保存对存储器和/或高速缓存的写入,以优化互连访问
这意味着将事物写入此缓冲区,然后在某些时候将缓冲区写入缓存.因此,缓存可以包含不是最新的数据视图,因此通过缓存一致性的另一个CPU也将不具有最新数据.存储缓冲区刷新是最新数据可见的必要条件,我认为这实际上是内存栅栏将在硬件级别发生的事情.
编辑:
对于您用作示例的代码,Wikipedia说:
可以在处理器#2分配给f之前插入存储器屏障,以确保在f的值改变时或之前其他处理器可以看到x的新值.