有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程Java内存模型volatile和x86

我试图理解java volatile的本质及其语义,以及它与底层架构和指令的转换。如果我们考虑以下博客和资源

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

以下是我收集的信息:

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

我很难理解的是:Java在x86上不发出LFENCE i、 e.读取挥发性物质不会导致LFENCE。。。。我知道x86的内存顺序防止了LOD/stored加载的重新排序,所以第二个要点已经解决了。但是,我假设,为了使该线程能够看到状态,应该发出LFENCE指令,以确保在执行围栏后的下一条指令之前(根据英特尔手册),所有加载缓冲区都已耗尽。我知道x86上有cahce一致性协议,但volatile read应该仍然会耗尽缓冲区中的任何负载,不是吗


共 (2) 个答案

  1. # 1 楼答案

    X86提供TSO。因此,在硬件层面上,您可以免费获得以下障碍[Load][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,所以以下围栏可以是无操作的:

    [LoadLoad][LoadStore][storestorestore]

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

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

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

  2. # 2 楼答案

    在x86上,缓冲区固定在缓存线上。如果缓存线丢失,则不会使用缓冲区中的值。因此,无需设置围栏或排空缓冲区;它们包含的值必须是当前值,因为如果不先使缓存线无效,另一个核心无法修改数据