考虑std::atomic<int> x(0)
。如果我理解正确,std::memory_order_relaxed
仅保证该操作是原子发生的,但不保证同步。因此,x.fetch_add(1, std::memory_order_relaxed)
来自2个线程的1000倍的最终结果始终为2000。但是,不能保证其中任何一个调用的返回值都能反映出真实的当前值(例如,第2000个增量可以返回1700作为前一个值)。
但是-这是我的困惑-鉴于这些增量是并行发生的,x.load(std::memory_order_acquire)
会返回什么?还是x.fetch_add(1, std::memory_order_acq_rel)
?这些返回的是当前的真实值还是由于缓和的增量而出现了与缓和的排序过时的问题相同的问题?
据我所知,该标准仅保证释放到同一对象上的获取同步,从而给出真实的当前值。那么如何轻松地将其与典型的获取-发布语义相结合?
例如,我听说std::shared_ptr
的引用计数以放松的顺序递增,以acq_rel的顺序递减,因为它需要确保它具有真实值才能仅删除该对象一次。因此,我很容易想到它们会给出真实的当前值,但是我似乎找不到任何标准语言来支持它。
答案 0 :(得分:0)
ISO C ++保证每个原子对象分别存在一个修改顺序。
使用seq_cst可以确保有一个全局顺序,所有线程都可以同意a
在b
之前更改。但是对于单个对象,即使放松某些操作,也可以保证存在修改顺序。
您从宽松的fetch_add
返回的值定义/记录了修改顺序。 第2000个增量按定义返回2000
,这就是您所知道的第2000个。
据我所知,该标准仅保证释放到获取(在相同变量上)的过程是同步的,从而给出真实的当前值。
仅当您关心读取 other 值(例如,一个线程存储到一个非原子数组,然后进行一个data_ready = 1;
之类的发布存储。为了使读者能够安全地从数组中读取数据,他们需要查看具有获取负载的data_ready != 0
,这意味着他们还可以查看执行发布存储的线程中所有较早分配的效果。