memory_order_relax负载vs volatile负载

memory_order_relaxed load vs volatile load

本文关键字:负载 vs volatile relax order memory      更新时间:2023-10-16

使用memory_order_relax读取atomic_uint的值与读取volatile unsigned int的值(假设volatile操作是原子操作)之间的区别是什么?

具体来说,让我们定义:

解决方案1

  1. "writer"线程写入atomic_uint(使用任何内存顺序限定符,从memory_order_relax到memory_order_seq_cst)
  2. "reader"线程对相同的atomic_uint进行原子放松读取

解决方案2

  1. volatile unsigned int
  2. "reader"线程读取该值

就其现状而言,我知道这两种情况都不能保证读取器读取写入器写入的值的能力。我试图理解的是volatile读取和轻松原子读取之间的区别。当考虑写后读一致性时,一个提供了什么而另一个没有?

我看到的唯一区别是:

  • volatile操作不能在它们之间重新排序,而原子负载可以与其他原子操作一起重新排序

还有别的吗?

volatile read不能保证是原子性的。这意味着您可以读取从未写入变量的值(也永远不会被程序的任何部分写入)。例如,如果您的应用程序只将0xAAAAAAAA0xBBBBBBBB写入变量,则volatile read可能产生0xAAAABBBB。或者其他任何事情,因为标准没有指定当volatile读和写出现在不同线程中而没有其他同步方式时的行为。

我不知道标准是否说它是UB或实现定义的。我只能说有一些实现(例如MSVC 2005)将非同步易失性读/写的行为定义为扩展。

使用memory_order_relaxed实际上为线程间通信提供了一个行为良好的volatile变量:

  • volatile最终以ABI(应用程序二进制接口)来指定,它是一个外部接口;volatile是与外部世界的接口:对这样的对象的访问是可观察行为的一部分,永远不能被优化掉;
  • 原子在内部语义方面被很好地指定;对象的表示不是规范的一部分;对这种对象的访问是抽象机器的一部分,有时可以被优化掉,或者在内部对进行推理(由编译器根据C/c++语义进行推理)。