为什么商店装载障碍被认为是昂贵的?

Wil*_*iam 12 concurrency multithreading cpu-architecture lock-free

大多数CPU架构都会重新订购存储加载操作,但我的问题是为什么?我对商店装载障碍的解释如下:

x = 50;
store_load_barrier;
y = z;
Run Code Online (Sandbox Code Playgroud)

此外,与发布和获取语义相比,我没有看到这种障碍如何在无锁编程中有多大用处.

Gab*_*ern 16

简答:存储加载障碍可防止处理器在存储加载障碍之后推测性地执行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
Run Code Online (Sandbox Code Playgroud)

当该序列执行时,该值r1将是需要很长时间才能完成的操作的结果.该指令ST r1, [ADDR1]必须停止直到r1被读取.与此同时,无序处理器可以推测性地执行该LD r3, [ADDR2]指令和其他指令,如果它们独立于早期存储.它们实际上不会在提交存储之前提交,但通过推测性地完成大部分工作,结果可以保存在重新排序缓冲区中并准备更快地提交.

这适用于单处理器系统,因为CPU可以检查ADDR1和ADDR2之间是否存在依赖关系.但是在多处理器系统中,多个CPU可以独立地执行加载和存储.可能有多个处理器正在执行ST到ADDR1和从ADDR2执行LD.如果CPU能够推测性地执行这些看起来没有依赖关系的指令,那么不同的CPU可能会看到不同的结果.我认为以下博客文章很好地解释了这是如何发生的(我认为这不是我能在这个答案中简明扼要地概括的内容).

现在考虑具有存储负载障碍的代码序列:

...             ;; 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
Run Code Online (Sandbox Code Playgroud)

这将防止LD r3, [ADDR2]指令和遵循相关指令被推测性地执行,直到先前的存储指令完成.这可能会降低CPU性能,因为整个CPU流水线可能必须在等待ST指令完成时停止,即使在CPU本身中LD和ST之间没有依赖性.

有些事情可以用来限制CPU停止的数量.但最重要的是,存储加载障碍会在加载和存储之间创建额外的依赖关系,这限制了CPU可以执行的推测执行量.

  • 将它与 LoadLoad、StoreStore 和 LoadStore 屏障进行比较会更有用。它们还会阻止 CPU 无序执行内存操作,不是吗?但不知何故,到目前为止我读过的所有文章都提到 StoreLoad 屏障是特殊的,而且更昂贵。 (2认同)