C++ 11内存排序 - 差异?

use*_*112 5 c++ concurrency multithreading atomic c++11

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

f.clear(std::memory_order_release);
bool x = f.test_and_set();
Run Code Online (Sandbox Code Playgroud)

但它说的是:

这里,调用clear()显式请求使用释放语义清除标志,而调用test_and_set() 使用默认内存排序来设置标志并检索旧值.

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

memory_order_relaxed
memory_order_release
memory_order_seq_cst
memory_order_consume
memory_order_acquire
memory_order_acq_rel
Run Code Online (Sandbox Code Playgroud)

nin*_*alj 1

非正式的表征(带着一袋盐来看待它):

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

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

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