在可变变量的上下文中,“后续读取”是什么意思?

2022-09-03 14:21:49

Java 内存可见性文档说:

对易失性字段的写入发生在每次后续读取该字段之前。

我很困惑后续在多线程上下文中意味着什么。这句话是否意味着所有处理器和内核都有一些全局时钟。例如,我在某个线程的周期c1中为变量赋值,然后第二个线程能够在随后的周期c1 + 1中看到这个值?


答案 1

在我看来,这就像是在说它在线程之间提供了无锁的获取/释放内存排序语义。参见Jeff Preshing的文章解释这个概念(主要是C++,但文章的重点是语言中立,关于无锁获取/释放同步的概念。

事实上,Java提供了顺序一致性,而不仅仅是acq/rel。但是,没有实际的锁定。请参阅 Jeff Preshing 的文章,了解为什么命名与你对锁执行的操作相匹配。volatile


如果读者看到您编写的值,那么它就知道在写入之前生产者线程中的所有内容也都已经发生。

此排序保证仅与有关单个线程排序的其他保证结合使用时才有用。

例如:

int data[100];
volatile bool data_ready = false;

制作人:

data[0..99] = stuff;
 // release store keeps previous ops above this line
data_ready = true;

消费者:

while(!data_ready){}     // spin until we see the write
// acquire-load keeps later ops below this line
int tmp = data[99];      // gets the value from the producer

如果不是易失性的,读取它不会在两个线程之间建立发生之前的关系。data_ready

您不必有自旋循环,您可以读取序列号或数组索引,然后读取 。volatile intdata[i]


我不太了解Java。我认为实际上可以为您提供顺序一致性,而不仅仅是发布/获取。顺序发布存储不允许在以后加载时重新排序,因此在典型硬件上,它需要一个昂贵的内存屏障,以确保在允许执行任何后续加载之前刷新本地核心的存储缓冲区。volatile

Volatile Vs Atomic解释了更多关于排序的信息。volatile

Java只是一个排序关键字;它等同于 C11 或 C++11 std::atomic<T> 它们还为您提供了原子 RMW 操作。在Java中,它不是原子增量,而是单独的加载和存储,就像.在Java中,你需要一个类,比如获得原子RMW。volatile_Atomicvolatile_var++volatile_var = volatile_var + 1AtomicInteger

请注意,C/C++根本不意味着原子性或顺序;它只告诉编译器假设该值可以异步修改。这只是您需要为除最简单的情况之外的任何内容编写无锁的一小部分。volatile


答案 2

这意味着一旦某个线程写入易失性字段,所有其他线程将观察到(在下次读取时)写入的值;但这并不能保护你免受种族的侵害。

线程有其缓存,这些缓存将被失效,并通过缓存一致性协议使用新写入的值进行更新。

编辑

后续意味着每当写入本身之后发生这种情况时。由于您不知道何时会发生的确切周期/时间,因此您通常会说,当其他线程观察写入时,它将观察在写入之前完成的所有操作;因此,波动性建立了先发生保证。

有点像一个例子:

 // Actions done in Thread A
 int a = 2;
 volatile int b = 3;


 // Actions done in Thread B
 if(b == 3) { // observer the volatile write
    // Thread B is guaranteed to see a = 2 here
 }

例如,您也可以循环(旋转等待)直到看到3。