3

鉴于:

std::atomic<uint64_t> x;

uint64_t f()
{
    x.store(20, std::memory_order::memory_order_relaxed);
    x.store(10, std::memory_order::memory_order_relaxed);
    return x.load(std::memory_order::memory_order_relaxed);
}

假设只有一个线程写入,是否有可能f返回一个值?对于非原子变量,这显然不是真的,但我不知道放松是否如此放松以至于它会忽略同一线程中的数据依赖关系?10x

4

1 回答 1

5

加载的结果总是 10(假设只有一个线程)。即使是宽松的原子变量也比非原子变量“更强”:

  1. 与非原子变量一样,所有线程必须同意对变量进行所有修改的单一顺序,
  2. 与非原子变量一样,该单一顺序与“sequenced before”关系一致,并且
  3. 该实现将保证潜在的并发访问将以某种方式将自己排序为所有线程都同意的某种顺序(从而满足要求1)。另一方面,在非原子变量的情况下,潜在的并发访问会导致未定义的行为。

一个宽松的原子变量不能用来同步不同的线程,除非伴随着明确的栅栏。与适用于原子变量的其他内存排序相比,这就是它放松的意义。

有关语言律师,请参阅 C++20 [intro.races]/10:

评估A 发生在评估B之前(或者,等效地,B发生在A之后),如果:

  • A在B之前排序,或 [...]

和 [intro.races]/15:

如果修改原子对象M的操作A发生在修改M的操作B之前,则在M的修改顺序中A应早于B。[注意:此要求称为写-写一致性。——尾注]

和 [intro.races]/18:

如果原子对象M上的副作用X发生在M的值计算B之前,则评估B应从X或从按照M的修改顺序跟随X的副作用Y获取其值。[注意:此要求称为读写一致性。——尾注]

因此,在您的程序中,20 的存储发生在 10 的存储之前(因为它在它之前排序)并且 10 的存储发生在加载之前。write-write coherence 要求保证 10 的存储发生在 20 的修改顺序之后。x当加载发生时,需要从 10 的存储中获取其值,因为 10 的存储发生在之前并且没有其他的修改可以跟在 10 的修改顺序之后的修改x

于 2021-10-26T15:25:24.027 回答