当前位置: 首页 > 知识库问答 >
问题:

易失性读和非易失性场

云浩然
2023-03-14

在阅读了这个问题和这个(尤其是第二个答案)之后,我对volatile及其关于记忆障碍的语义感到非常困惑。

在上面的例子中,我们写入一个易失性变量,这会导致一个mitch,这反过来会将所有挂起的存储缓冲区/加载缓冲区刷新到主缓存,使其他缓存行无效。

然而,非易失性字段可以优化并存储在寄存器中,例如?那么,我们如何才能确保给定一个写入易失性变量之前的所有状态变化都是可见的呢?如果我们有1000件东西呢?

共有3个答案

刘丰羽
2023-03-14

编译器负责确保保留内存模型的语义学。在您的示例中,编译器将确保在易失性写入之前将任何跨线程可见值写入内存(在x86上,普通存储就足够了)。

蓝慈
2023-03-14

在上面的例子中,我们写入一个易失性变量,这会导致一个mitch,这反过来会将所有挂起的存储缓冲区/加载缓冲区刷新到主缓存...

这是正确的。

使其他缓存行无效。

这是不正确的,或者至少是误导性的。使其他缓存线失效的不是写内存屏障。其他处理器中运行的读内存屏障会使每个处理器的缓存线失效。内存同步是线程写入和其他线程从volatile变量读取之间的协作行为。

Java内存模型实际上保证,只有读取写入的同一变量,才能保证该变量被更新。事实上,所有的内存缓存线都会在写入内存屏障被跨越时被刷新,而当读内存屏障被跨越时,所有的内存缓存线都会失效——不管访问的变量是什么。

然而,非易失性字段可以优化并存储在寄存器中,例如?那么我们如何能够确定给定一个写到易失性变量ALL之前的状态变化将是可见的呢?如果我们改变1000件事呢?

根据这个留档(和其他),内存障碍也会导致编译器生成刷新寄存器的代码。引用:

... 在使用barrier()时,编译器必须丢弃当前缓存在任何机器寄存器中的所有内存位置的值。

盖弘毅
2023-03-14

JMM提供的保证是——如果线程1写入一个易失性变量,然后线程2读取同一个易失性变量,那么线程2保证在写入易失性变量之前看到线程1所做的所有更改(包括对非易失性变量所做的更改)。这是一个强有力的保证,每个人都同意。

然而,保证只适用于线程2看到的内容。您可能还有另一个线程thread 3,它可能看不到线程1设置的非易失性字段的最新值(thread 3可能有并且允许缓存这些非易失性字段的值)。只有在线程3读取相同的volatile之后,才能保证看到来自线程1的非volatile写入

 类似资料:
  • 我对下面的代码段有一个问题。结果可能有一个结果[0,1,0](这是用JCStress执行的测试)。那么这是怎么发生的呢?我认为数据写入(data=1)应该在Actor2(guard2=1)中写入到guard2之前执行。我说得对吗?我问,因为很多时候我读到挥发物周围的说明没有重新排序。此外,根据这一点:http://tutorials.jenkov.com/java-concurrency/vola

  • 如果是,如果被添加到数组中,强制转换会受到什么影响?谢谢你! 编辑:@cacahuete Frito链接了一个非常相似的问题:带有'volatile'数组的'memcpy((void*)dest,src,n)'安全吗?

  • 它几乎是线程安全的单例的正确实现。我看到的唯一问题是: 初始化字段的可以在完全初始化之前发布。现在,第二个线程可以在不一致的状态下读取。 但是,在我看来,这只是问题。这是唯一的问题吗?(并且我们可以使不稳定)。

  • 问题内容: 我尝试了解为什么此示例是正确同步的程序: 由于存在冲突的访问(存在对a的写入和读取),因此在每个顺序一致性中,必须在访问之间的关系之前执行。假设顺序执行之一: 是1发生-在2之前发生,为什么? 问题答案: 不,在相同变量的易失性写入之前(以同步顺序),在易失性写入 之前 不一定 会发生 易失性读取。 这意味着它们可能处于“数据争用”中,因为它们“冲突的访问未按先发生后关系进行排序”。如

  • 我正在使用一个API,该API为内存映射的I/O提供指针。它通过填写指针到指针的参数来实现这一点: 因为这是内存映射的I/O,所以我很确定我应该在这里使用。(我不知道为什么他们没有将参数设为。) 但是,我的volatile void**不能隐式转换为函数的,因此我不能直接传入它: 我目前正在使用一个额外的变量和一个单独的赋值步骤来解决这个问题: 这似乎很冗长。在这种情况下,当指针传入时,将vola

  • 来自C/C++,我对Java中的volatile对象行为有点困惑。 null faik,volatile意味着b引用的“book对象”应该在主内存中。编译器可能在内部实现引用作为指针,因此b指针可能位于缓存中。我的理解是,volatile是对象的限定符,而不是引用/指针的限定符。 问题是:在使用方法中,本地引用不是易失性的。这个“本地”引用会不会把底层的Book对象从主存带到缓存中,实质上使对象不