c++ - 混合松弛和释放-获取内存顺序
问题描述
考虑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 的顺序递减,因为它需要确保它具有真实值才能只删除一次对象。因此,我很想他们会给出真实的当前值,但我似乎找不到任何标准来支持它。
解决方案
ISO C++ 保证每个原子对象分别存在一个修改顺序。
使用 seq_cst 可以保证有一个全局顺序,所有线程都可以就a
之前的更改b
或其他内容达成一致。但是对于单个对象,即使放宽了一些操作,也保证存在修改顺序。
您轻松fetch_add
定义/记录修改顺序的返回值。 根据定义,第 2000 个增量返回,这就是您知道它是第 2000 个的方式。2000
据我所知,该标准仅保证释放到获取(在同一变量上)同步,从而给出真实的当前值。
仅当您关心读取其他值时才需要同步,例如,一个线程存储到非原子数组,然后执行释放存储,如data_ready = 1;
. 为了让读者安全地从数组中读取数据,他们需要data_ready != 0
通过获取加载来查看,这意味着他们还可以查看执行释放存储的线程中所有早期分配的效果。
推荐阅读
- python - TfidfVectorizer的词汇表和get_features()之间的区别?
- html - 如何使用 CSS 创建 3 段甜甜圈/环?
- java - Delete 和 DeleteById 方法在 Hibernate 中不起作用
- java - 错误:无法找到或加载主类 -Xms1G
- vba - vba scrape html - 获取具有动态类的元素
- user-interface - 在 Tkinter GUI 中嵌入散景和大数据
- javascript - 在 JavaScript 中使用 setInterval 循环时如何让精灵停止移动
- javascript - 选中复选框时,如何将表单控件的所有值传递给另一个表单?
- android-studio - 如何在 Google Play 音乐中添加浮动活动,例如“正在播放音乐”
- r - 为什么这段代码使用 == 和 | 运算符的结果为 TRUE