【问题标题】:C++11 memory orderings- the differences?C++11 内存排序——区别?
【发布时间】:2014-04-10 21:44:46
【问题描述】:

我目前正在阅读 Concurrency in Action,在第 111 页上,它提供了与 std::atomic_flag 相关的示例代码,以解释内存排序的工作原理:

f.clear(std::memory_order_release);
bool x = f.test_and_set();

但它只是说:

这里,对clear()的调用明确要求标志是 使用释放语义清除,而对 test_and_set() 的调用 使用默认内存顺序设置标志和检索 旧值。

他们实际上并没有解释差异是什么。有人可以提供这些内存排序如何工作的一般概述吗?所以不仅仅是我上面提到的,我相信还有更多:

memory_order_relaxed
memory_order_release
memory_order_seq_cst
memory_order_consume
memory_order_acquire
memory_order_acq_rel

【问题讨论】:

  • 他们在这里有一个不错的概述en.cppreference.com/w/cpp/atomic/memory_order
  • 您能否解释一下这是什么意思:“具有此内存顺序的加载操作对受影响的内存位置执行消耗操作:先前写入由执行释放操作对该线程可见。”
  • @user997112:进一步阅读该 memory_order 文档。他们解释了获取和消费之间的区别。 Acquire 使释放之前的所有先前内存操作可见。消耗只会使对原子变量有影响的可见内存。它还说,他们所知道的唯一能发挥作用的 CPU 是 Alpha。但这并不能保证将来不会有人重用该内存设计。
  • 如果您继续阅读本书,它将比您想要的更详细地解释所有差异。

标签: c++ multithreading c++11 concurrency atomic


【解决方案1】:

非正式表征(带上一袋盐):

  • SEQ_CST:代码的行为就像是简单的线程交错,没有可观察到的重新排序,只要没有数据竞争。
  • RELEASE/ACQUIRE: 发布“发布”一次写入,并且在同一内存位置上的读取与该写入同步。例如,互斥锁可以执行ACQUIRE,而互斥锁可以解锁RELEASE。另一个例子:

示例(括号中标有其内存顺序的原子操作):

t1:                                   t2:
   data = foo                            while not data_valid; (ACQUIRE)
   data_valid = true; (RELEASE)          bar = data;
  • ACQ_REL: 对原子 RMW(读取-修改-写入)操作进行获取和释放。请注意,您可以指定对成功的 RMW 使用 ACQ_REL,如果 RMW 操作失败,则使用另一个内存顺序。
  • RELEASE/CONSUME:您发布一个指向结构的指针,读取“消耗”该发布,并可以访问指向的数据。一些 Alpha 处理器具有拆分缓存,这意味着您可能正在从缓存组中读取指针,而指向的数据可能不在该缓存的其他组中。在 Linux 上实现的 RCU 中,rcu_derefence() 负责在 Alpha 上的指针读取与其取消引用之间插入一个读取屏障。请注意,已经有一些关于完全改变消耗内存顺序规范的讨论(在一个名为 "arch: atomic rework" 的邮件列表线程上),因为这对于编译器编写者来说似乎是不切实际的。特别是,当前标准允许您发布p,而*(q + (p-p)) 依赖于此。有些人认为这根本没有意义。
  • 放松:对所有人免费。

【讨论】:

  • 即使存在竞争条件,seq_cst 也只是保证所有线程都会遵守一些任意顺序。
  • @Leeor:好吧,我用错了术语。应该是调用未定义行为的数据竞争
猜你喜欢
  • 2020-01-06
  • 1970-01-01
  • 1970-01-01
  • 2021-08-31
  • 2017-01-26
  • 1970-01-01
  • 2015-11-19
  • 1970-01-01
相关资源
最近更新 更多