void loop(int loops)
{
while (loops-- > 0)
asm volatile ("" : : : "memory")
}
我知道asm volatile ("" : : : "memory")
会阻止编译器重新排序指令。但是,在这里,我看不出可以重新排序的内容以及为什么它在并发方面可能会出现问题。 (我考虑到可能的中断)。那么,为什么会有障碍?
第二,关联问题。 我们假设我们有10000000行代码(见下文)。我们知道CPU可以重新排序StoreLoad。
mov [eax],$ 2; NOP; NOP; ...; NOP; mov ebx,[ecx];
CPU能够预测有多少机会应用StoreLoad?
同样的问题可以应用于编译器,但它涉及各种重新排序(不仅是StoreLoad而且不仅仅是内存操作)
答案 0 :(得分:2)
TL:DR :问题在于您只是将其视为std::atomic_thread_fence(std::memory_order_seq_cst)
,但这不是GNU C {{1}语句做。
是的,很明显,这是一个令人讨厌的忙等待延迟循环的障碍。请记住,易变volatile asm
语句不能与任何其他C语句重新排序,而不仅仅是内存操作。
asm
即使没有强制所有可到达的内存都是最新的并被视为破坏,我们仍然会得到一个循环。因此void loop_nomemclobber(int loops) {
do { // loop rearranged for simpler asm
asm volatile ("" : : : /* "memory" */ );
} while (--loops > 0);
}
loop_nomemclobber:
.L3:
sub edi, 1
test edi, edi
jg .L3
ret
语句执行此操作的原因与asm volatile
clobber无关。
"memory"
是具有自动存储功能的本地用户。编译器可以证明没有任何东西(包括asm语句)有任何方法可以确定它在内存中的位置,因此它根本不必存在于内存中。
CPU能够预测有多少机会应用StoreLoad?
CPU不会无缘无故地寻找重新排序内存的机会!重新排序自然发生(除非用MFENCE阻止),因为CPU需要缓冲存储,直到它确定它们不是推测性的,并且在缓存未命中存储上。因此它将商店放入商店缓冲区,并最终提交缓存。
在CPU里面没有一个小恶魔说"啊哈,这是另一个让Gilgamesz难上的机会,也许我这次重新排序真的骗他了! "
这里有一个真正的问题,那就是在特定的微体系结构之前,两个指令需要相隔多远(在时间上,或在insn的数量上,或者介入的负载/存储的数量)这个商店有足够的无序资源可以缓存,直到加载完毕为止。
我不知道,但由于StoreStore重新排序是不允许的,因此高速竞争缓存行的缓存缺失存储无法等待获取对缓存行的访问权限数以百万计的其他指令运行除非这些说明都不是商店。
我不知道答案,但我认为理论上可以在Intel Haswell上推迟数百个周期的商店,可能只受硬件仲裁机制的公平算法的限制。处理多个核争用访问同一缓存行的情况。
我忘记了我所读过的关于现代英特尔硬件是否以这种方式工作的内容,但我认为也许商店可以退出无序内核,但仍然没有提交到L1缓存。相反,它只在商店队列中作为肯定会发生的商店。这将使缓存缺失存储避免阻止新指令进入ROB。 (加载需要探测存储缓冲区以保持单核内的正确执行,但这样做并不需要ROB也跟踪存储)。