我无法理解 JSR-133 Coookbook 中 StoreLoad 屏障的定义.
Store1; StoreLoad; Load2
StoreLoad barriers protect against a subsequent load incorrectly using Store1's data value rather than that from a more recent store to the same location performed by a different processor.
这是否意味着在没有 StoreLoad 屏障的情况下,处理器可以将 Store1 存储到其写入缓冲区并从其写入缓冲区加载该存储值,即使其他处理器已写入Store1 和 Load1 之间相同的内存位置并刷新到缓存?
最佳答案
是的,这是可能的,具体取决于内存排序模型。
写缓冲区通常是预调度的,这意味着外部世界尚无法观察到其中的存储。然而,为了获得更好的性能,大多数微架构允许在同一线程上执行较年轻的负载,并且如果地址与存储的地址匹配 - 可以执行数据转发以使程序尽可能快地继续,同时使负载看起来好像它是在商店之后完成的。
这对于线程内一致性来说工作得很好,但是当外部处理器访问相同的地址并可能更改数据时,负载可能来不及看到它(尽管在许多 CPU 上,如果负载可能仍然被捕获尚未完成,机器将自行修复)。
我不完全确定引用的意思是什么,但我认为可以用这个场景更好地证明这一点:
CPU0: CPU1:
store [x]<--1
store [x]<--2
store [y]<--2
load r1<--[x]
load r2<--[y]
没有障碍的可能结果(理论上)是 r1 == 1, r2 == 2
,这意味着 CPU1 的两个存储都已经执行(因为我们从 2
读取了 [y]
),但不知何故 [x]
的旧值幸存下来(因为它被转发了)。
我不太喜欢这个例子,首先是因为,正如我所说,大多数 CPU 应该成功地监听出该加载的旧值,即使它已执行。其次 - 它过于复杂,因为他们坚持声称:
a StoreLoad is strictly necessary only for separating stores from subsequent loads of the same location(s) as were stored before the barrier
这是错误的,本地址不同时也需要屏障,如以下(经典)示例所示:
CPU0: CPU1:
store [x]<--1 store [y]<--1
load r1<--[y] load r2<--[x]
这里的地址是不同的,仍然需要一个屏障来防止两个加载都读取旧值的情况(即使必须执行两个存储才能到达那里),这要归功于加载的乱序执行.请注意,这是一个与提出的问题(存储到负载转发)不同的问题,但它证明引用是错误的。
关于java - StoreLoad内存屏障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21148085/