简体   繁体   English

易读和非易失性字段

[英]Volatile read and non-volatile fields

After reading this question and this (especially second answer) I am massively confused about volatile and its semantics with respect to memory barriers. 在阅读了这个问题这个 (尤其是第二个答案)之后,我对volatile及其关于内存障碍的语义感到非常困惑。

In the above examples, we write to a volatile variable, which causes an mfence, which in turn flushes all pending store buffers/load buffers to main cache, invalidating other cache lines. 在上面的示例中,我们写入一个volatile变量,这会导致mfence,进而将所有未决的存储缓冲区/加载缓冲区刷新到主缓存中,从而使其他缓存行无效。

However, the non-volatile fields could be optimized and be stored in registers for example? 但是,可以优化非易失性字段并将其存储在寄存器中吗? So how can we be sure that given a write to volatile variable ALL state changes prior to it will be visible? 那么,如何确定在写入易失变量之前,所有状态更改都可见? What if we cahnge 1000 things? 如果我们处理1000件事怎么办?

The guarantee that the JMM gives is - if Thread 1 writes a volatile variable and after that Thread 2 reads that same volatile variable, then Thread 2 is guaranteed to see all changes made by Thread 1 prior to writing the volatile variable (including changes made to non-volatile variables). JMM的保证是-如果线程1编写了一个volatile变量,然后线程2读取了相同的volatile变量,那么在编写volatile变量之前,线程2 可以保证看到线程1所做的所有更改(包括对volatile所做的更改)。非易失性变量)。 This is a strong guarantee that exists and everyone agrees to. 这是存在并且每个人都同意的有力保证。

However, the guarantee applies only to what Thread 2 sees. 但是,此保证仅适用于线程2看到的内容。 You may still have another thread, Thread 3, which may NOT see up-to-date values for the non-volatile fields set by Thread 1 (Thread 3 may have, and is allowed to, cache values for those non-volatile fields). 您可能还有另一个线程,线程3,可能看不到线程1设置的非易失性字段的最新值 (线程3可能具有并允许缓存那些非易失性字段的值) 。 Only after Thread 3 reads the same volatile is it guaranteed to see non-volatile writes from Thread 1 只有在线程3读取相同的volatile之后,才能保证看到来自线程1的非易失性写入

In the above examples, we write to a volatile variable, which causes an mfence, which in turn flushes all pending store buffers/load buffers to main cache... 在上面的示例中,我们写入一个volatile变量,这会导致mfence,进而将所有未决的存储缓冲区/加载缓冲区刷新到主缓存中。

This is correct. 这是对的。

invalidating other cache lines. 使其他缓存行无效。

This is not correct or at least is misleading. 这是不正确的,或者至少是误导的。 It is not the write memory-barrier which invalidates the other cache lines. 不是使其他高速缓存行无效的写存储器屏障。 It is the read memory-barrier running in the other processors which invalidates each processor's cache lines. 是在其他处理器中运行的读取内存屏障使每个处理器的缓存行无效。 Memory synchronization is cooperative action between the thread writing and the other threads reading from volatile variables. 内存同步是线程写入和其他线程从volatile变量读取之间的协作动作。

The Java memory model actually guarantees that only a read of the same variable that was written to will the variable be guaranteed to be updated. Java内存模型实际上保证只有对写入的同一变量的读取才能保证该变量被更新。 The reality is that all memory cache lines are flushed upon a write memory barrier being crossed and all memory cache lines are invalidated when a read memory barrier is crossed – regardless of the variable being accessed. 现实情况是,越过写入内存屏障, 所有内存缓存行都将被刷新,而越过读取内存屏障,则所有内存缓存行均将失效(与访问变量无关)。

However, the non-volatile fields could be optimized and be stored in registers for example? 但是,可以优化非易失性字段并将其存储在寄存器中吗? So how can we be sure that given a write to volatile variable ALL state changes prior to it will be visible? 那么,如何确定在写入易失变量之前,所有状态更改都可见? What if we change 1000 things? 如果我们改变1000件事该怎么办?

According to this documentation (and others), memory barriers also cause the compiler to generate code that flushes registers as well. 根据本文档 (和其他文档 ),内存障碍还导致编译器生成也会刷新寄存器的代码。 To quote: 报价:

... while with barrier() the compiler must discard the value of all memory locations that it has currently cached in any machine registers. ...当使用barrier()时,编译器必须丢弃当前已缓存在任何机器寄存器中的所有内存位置的值。

The compiler is responsible for ensuring the semantics of the memory model are preserved. 编译器负责确保保留内存模型的语义。 In your example, the compiler would ensure that any cross-thread visible values are written to memory prior to the volatile write (on x86 a plain store is sufficient for this purpose). 在您的示例中,编译器将确保在进行易失性写入之前将任何跨线程可见值写入内存(在x86上,一个普通存储足以实现此目的)。

Volatile variables share the visibility features of synchronized, but none of the atomicity features. 易变变量共享已同步的可见性功能,但没有原子性功能。 This means that threads will automatically see the most up-to-date value for volatile variables. 这意味着线程将自动查看volatile变量的最新值。

You can use volatile variables instead of locks only under a restricted set of circumstances. 仅在少数情况下,才可以使用易失性变量而不是锁。 Both of the following criteria must be met for volatile variables to provide the desired thread-safety: 对于可变变量,必须满足以下两个条件才能提供所需的线程安全性:

Writes to the variable do not depend on its current value. 写入变量不取决于其当前值。

The variable does not participate in invariant with other variables. 该变量不参与其他变量的不变式。

您可以观看此JMM说明视频 ,以向您清楚JMM的工作原理

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果直接从内存中读取易失性字段,那么从哪里读取非易失性字段? - If volatile fields are read directly from memory, where are non-volatile fields read from? 混合挥发性和非挥发性 - Mixing volatile and non-volatile 了解Java中的易失性和非易失性读/写 - Understanding volatile and non-volatile read/write in Java 易失性和非易失性字段混合时发生易失性关系 - Volatile happens-before relationship when there's mix of volatile and non-volatile fields Java用非易失性对易失性写进行重新排序 - Java reordering volatile write with non-volatile volatile 会影响非易失性变量吗? - Does volatile influence non-volatile variables? 非易失性写入的可见性 - viewability of a non-volatile write 对非易失性字段的同步访问是否安全? - Is synchronized access to non-volatile fields thread safe? 发生在与Java中的易失性字段和同步块的关系之前 - 以及它们对非易失性变量的影响? - Happens-before relationships with volatile fields and synchronized blocks in Java - and their impact on non-volatile variables? compareAndSwap 一个普通成员(非易失性成员)仍然具有易失性读写的内存语义 - compareAndSwap a common member ( non-volatile member ) still has memory semantics of volatile read and write
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM