大多数CPU架构都会重新订购存储加载操作,但我的问题是为什么?我对商店装载障碍的解释如下:
x = 50;
store_load_barrier;
y = z;
此外,与发布和获取语义相比,我没有看到这种障碍在无锁编程中有多大用处。
答案 0 :(得分:14)
简短回答:存储加载障碍可防止处理器推测性地执行存储加载障碍之后的LOAD,直到所有先前存储完成为止。
<强>详情:
存储装载障碍是昂贵的原因是它阻止了跨屏障的LOAD和STORE操作的重新排序。
假设你有一个如下的指令序列:
... ;; long latency operation to compute r1
ST r1, [ADDR1] ;; store value in r1 to memory location referenced by ADDR1
LD r3, [ADDR2] ;; load r3 with value in memory location ADDR2
... ;; instructions that use result in r3
当执行此序列时,r1
的值将是需要很长时间才能完成的操作的结果。指令ST r1, [ADDR1]
必须停止,直到读取r1
同时,如果无序处理器独立于早期存储,则可以推测性地执行LD r3, [ADDR2]
和其他指令。它们实际上不会在提交商店之前提交,但是通过推测性地完成大部分工作,结果可以保存在重新排序缓冲区中并准备好更快地提交。
这适用于单处理器系统,因为CPU可以检查ADDR1和ADDR2之间是否存在依赖关系。但是在多处理器系统中,多个CPU可以独立地执行加载和存储。可能有多个处理器正在执行ST到ADDR1和从ADDR2执行LD。如果CPU能够推测性地执行这些看起来没有依赖关系的指令,那么不同的CPU可能会看到不同的结果。我认为following blog post很好地解释了这种情况如何发生(我认为这不是我能在这个答案中简明扼要地总结的。)
现在考虑具有存储加载障碍的代码序列:
... ;; long latency operation to compute r1
ST r1, [ADDR1] ;; store value in r1 to memory location referenced by ADDR1
ST_LD_BARRIER ;; store-load barrier
LD r3, [ADDR2] ;; load r3 with value in memory location ADDR2
... ;; instructions that use result in r3
这将阻止LD r3, [ADDR2]
指令和以下相关指令被推测性地执行,直到先前的存储指令完成。这可能会降低CPU性能,因为整个CPU流水线可能必须在等待ST指令完成时停止,即使在CPU本身中LD和ST之间没有依赖关系。
可以采取一些措施限制CPU停止的数量。但最重要的是,存储加载障碍会在加载和存储之间创建额外的依赖关系,这限制了CPU可以执行的推测执行量。