混合放松和释放获取内存顺序

Mixing Relaxed and Release-Acquire Memory Orders

本文关键字:获取 内存 顺序 释放 混合      更新时间:2023-10-16

考虑std::atomic<int> x(0)。如果我理解正确的话,std::memory_order_relaxed只保证操作以原子方式发生,但不保证同步。因此,来自2个线程的x.fetch_add(1, std::memory_order_relaxed)1000次将始终具有2000的最终结果。然而,这些调用中任何一个的返回值都不能保证反映真实的当前值(例如,第2000次增量可以返回1700作为以前的值)。

但是——这是我的困惑——考虑到这些增量是并行发生的,x.load(std::memory_order_acquire)会返回什么?还是x.fetch_add(1, std::memory_order_acq_rel)?这些是否返回真实的当前值,或者它们是否存在与由于放松增量而导致的放松排序相同的过期答案问题?

据我所知,该标准只保证释放到获取(在同一变量上)是同步的,从而给出真实的当前值。那么,轻松如何与典型的获取发布语义相结合呢?

例如,我听说std::shared_ptr的引用计数按松弛顺序递增,按acq_rel顺序递减,因为它需要确保它具有真值才能只删除一次对象。正因为如此,我很想他们会给出真实的当前价值,但我似乎找不到任何标准来支持它。

ISO C++保证每个原子对象分别存在修改顺序。

使用seq_cst,可以保证存在一个全局顺序,其中所有线程都可以就ab之前的更改达成一致。但对于单个对象,即使放松了一些操作,也保证存在修改顺序。

放松fetch_add的返回值定义/记录修改顺序根据定义,第2000次增量返回2000,这就是为什么您知道它是第2000次

据我所知,该标准只保证释放到获取(在同一变量上)同步,从而给出真实的当前值。

只有当您关心读取其他值时,才需要同步,例如一个线程存储到非原子数组,然后执行像data_ready = 1;这样的发布存储。为了让读取器安全地从数组中读取数据,他们需要看到带有获取负载的data_ready != 0,这意味着他们还可以看到执行发布存储的线程中所有早期分配的效果。