7

我无法理解JSR-133 Cookbook中StoreLoad屏障的定义。

商店1;存储加载;加载2

StoreLoad 屏障使用 Store1 的数据值而不是从更新的存储到由不同处理器执行的相同位置的数据值来防止后续加载不正确。

这是否意味着如果没有StoreLoad屏障,处理器可以将 Store1 存储到其写入缓冲区并从其写入缓冲区加载此存储的值,即使其他一些处理器写入相同的内存位置并刷新到 Store1 和之间的缓存负载1?

4

1 回答 1

6

是的,这是可能的,具体取决于内存排序模型。

写缓冲区通常是预先调度的,这意味着其中的存储还不能被外界观察到。但是,为了获得更好的性能,大多数微架构允许在同一线程上执行较年轻的加载,并且如果地址与存储的地址匹配 - 可以执行数据转发以使程序尽可能快地继续,同时使加载看起来好像它是在商店之后完成的。

这对于线程内的一致性很好,但是当外部处理器访问相同的地址并可能更改数据时,负载看到这一点可能为时已晚(尽管在许多 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 应该成功地窥探到该负载的旧值,即使在它执行之后也是如此。其次 - 它过于复杂,因为他们坚持声称:

StoreLoad 仅用于将存储与在屏障之前存储的相同位置的后续加载分开时是严格必需的

这是错误的,当地址不同时也需要屏障,如以下(经典)示例所示:

CPU0:                              CPU1: 
store [x]<--1                      store [y]<--1
load  r1<--[y]                     load r2<--[x]

这里的地址是不同的,并且仍然需要一个屏障来防止两个加载都读取旧值的情况(即使两个存储都必须执行才能到达那里),这要归功于加载的无序执行。请注意,这与提出的问题(存储到负载转发)不同,但它证明了引用是错误的。

于 2014-01-15T22:54:31.627 回答