【问题标题】:Java memory model - volatile and x86Java 内存模型 - volatile 和 x86
【发布时间】:2017-04-27 21:31:27
【问题描述】:

我正在尝试理解 java volatile 的内在特性及其语义,以及它对底层架构及其指令的转换。如果我们考虑以下博客和资源

fences generated for volatileWhat gets generated for read/write of volatileStack overflow question on fences

这是我收集的:

  • volatile read 在其后插入 loadStore/LoadLoad 屏障(x86 上的 LFENCE 指令)
  • 它可以防止在后续写入/加载时重新排序加载
  • 它应该保证加载由其他线程修改的全局状态,即在 LFENCE 之后,其他线程所做的状态修改对其 CPU 上的当前线程是可见的。

我很难理解的是:Java 在 x86 上不会发出 LFENCE 即读取 volatile 不会导致 LFENCE.... 我知道 x86 的内存排序会阻止重新排序加载的 lods/stored,因此要处理第二个要点。但是,我假设为了使该线程可见状态,应该发出 LFENCE 指令以保证在执行栅栏后的下一条指令之前耗尽所有 LOAD 缓冲区(根据英特尔手册)。我知道 x86 上有 cahce 一致性协议,但是 volatile 读取仍然应该耗尽缓冲区中的任何负载,不是吗?

【问题讨论】:

  • 您似乎忘记了 Java 是独立于平台的。
  • @JacobG.:平台无关与否,Java 实现不是平台无关的,我们仍然可以询问有关 Java 实现如何表现的问题。

标签: java multithreading cpu volatile java-memory-model


【解决方案1】:

在 x86 上,缓冲区被固定到高速缓存行。如果高速缓存行丢失,则不使用缓冲区中的值。所以没有必要隔离或排空缓冲区;它们包含的值必须是最新的,因为如果不先使缓存行失效,另一个内核无法修改数据。

【讨论】:

  • 对不起,你是说我不需要lfence,因为当实际加载发生时,缓存行无效,那些加载缓冲区会被doscarded? IE。 lfence 的发生有点懒惰?
  • 是的,完全正确。缓冲区被固定到高速缓存行。如果缓存行无效,则缓存读取也无效。因此,虽然 x86 确实预取读取,但它永远不能使用过时的值。 (当然,这只是 x86 的东西。)
  • 寄存器中可能存在的其他变量呢?我认为也需要卸载一些注册表,不是吗?
  • @Bober02 JVM 不会将volatiles 存储在寄存器中。
  • 不不,不是易失性 - 我们有易失性 x,以及在写入 x 之前更改的其他变量。但是,在读取 x 的值后,所有变量的更改都是可见的。因此,那些可能在寄存器中的变量显然也需要清除
【解决方案2】:

X86 提供 TSO。因此,在硬件层面上,您可以免费获得以下障碍 [LoadLoad][LoadStore][StoreStore]。唯一缺少的是 [StoreLoad]。

负载具有获取语义

r1=X
[LoadLoad]
[LoadStore]

商店具有发布语义

[LoadStore]
[StoreStore]
Y=r2

如果您先进行存储然后加载,您最终会得到以下结果:

[LoadStore]
[StoreStore]
Y=r2
r1=X
[LoadLoad]
[LoadStore]

问题是加载和存储仍然可以重新排序,因此它不是顺序一致的;这对于 Java 内存模型是强制性的。他们防止这种情况的唯一方法是使用 [StoreLoad]。

[LoadStore]
[StoreStore]
Y=r2
[StoreLoad]
r1=X
[LoadLoad]
[LoadStore]

最合乎逻辑的地方是将其添加到写入中,因为通常读取比写入更频繁。所以写会变成:

[LoadStore]
[StoreStore]
Y=r2
[StoreLoad]

由于 X86 提供了 TSO,以下栅栏可以是无操作的:

[加载加载][加载存储][存储存储]

所以唯一相关的是 [StoreLoad],这可以通过 MFENCElock addl %(RSP),0 来完成

LFENCE 和 SFENCE 与这种情况无关。 LFENCE 和 SFENCE 用于弱排序的加载和存储(例如 SSE 的加载和存储)。

[StoreLoad] 在 X86 上的作用是停止执行加载,直到存储缓冲区被耗尽。这将确保在存储全局可见(离开存储缓冲区并进入 L1d)之后加载是全局可见的(因此从内存/缓存中读取)。

【讨论】:

    猜你喜欢
    • 2020-07-03
    • 1970-01-01
    • 2019-04-06
    • 1970-01-01
    • 2013-12-31
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多