c++ - 每个 memory_order 是什么意思?

标签 c++ c++11 thread-safety atomic memory-model

我读了一章,我不太喜欢它。我仍然不清楚每个内存顺序之间的区别是什么。这是我目前的猜测,在阅读了更简单的 http://en.cppreference.com/w/cpp/atomic/memory_order 后,我明白了这一点。

以下是错误的所以不要试图学习它

  • memory_order_relaxed:不同步,但在不同原子变量中从另一种模式完成订单时不会被忽略
  • memory_order_consume:同步读取这个原子变量,但是它不同步在此之前写入的宽松变量。但是,如果线程在修改 Y(并释放它)时使用 var X。其他消耗 Y 的线程也会看到 X 被释放?我不知道这是否意味着这个线程推出了 x(显然是 y)的变化
  • memory_order_acquire:同步读取此原子变量并确保同步之前写入的宽松变量。 (这是否意味着所有线程上的所有原子变量都已同步?)
  • memory_order_release:将原子存储推送到其他线程(但仅当它们使用消耗/获取读取 var 时)
  • memory_order_acq_rel:用于读/写操作。执行获取以便您不会修改旧值并发布更改。
  • memory_order_seq_cst:与获取释放相同,除了它强制在其他线程中看到更新(如果 a 在另一个线程上使用relaxed 存储。我将 b 与 seq_cst 存储。第三个线程读取 a 与relax 将看到随 b 和任何其他原子变量一起变化?)。

  • 我想我明白了,但如果我错了,请纠正我。我找不到任何用易于阅读的英语解释它的内容。

    最佳答案

    GCC Wiki 给出了 very thorough and easy to understand explanation带有代码示例。

    (编辑摘录,并添加重点)

    重要的:

    在将我自己的措辞添加到答案的过程中重新阅读从 GCC Wiki 复制的以下引用后,我注意到该引用实际上是错误的。他们以错误的方式获取和消费。 release-consume 操作仅提供对相关数据的排序保证,而 release-acquire 操作提供该保证,而不管数据是否依赖于原子值。

    The first model is "sequentially consistent". This is the default mode used when none is specified, and it is the most restrictive. It can also be explicitly specified via memory_order_seq_cst. It provides the same restrictions and limitation to moving loads around that sequential programmers are inherently familiar with, except it applies across threads.
    [...]
    From a practical point of view, this amounts to all atomic operations acting as optimization barriers. It's OK to re-order things between atomic operations, but not across the operation. Thread local stuff is also unaffected since there is no visibility to other threads. [...] This mode also provides consistency across all threads.

    The opposite approach is memory_order_relaxed. This model allows for much less synchronization by removing the happens-before restrictions. These types of atomic operations can also have various optimizations performed on them, such as dead store removal and commoning. [...] Without any happens-before edges, no thread can count on a specific ordering from another thread.
    The relaxed mode is most commonly used when the programmer simply wants a variable to be atomic in nature rather than using it to synchronize threads for other shared memory data.

    The third mode (memory_order_acquire / memory_order_release) is a hybrid between the other two. The acquire/release mode is similar to the sequentially consistent mode, except it only applies a happens-before relationship to dependent variables. This allows for a relaxing of the synchronization required between independent reads of independent writes.

    memory_order_consume is a further subtle refinement in the release/acquire memory model that relaxes the requirements slightly by removing the happens before ordering on non-dependent shared variables as well.
    [...]
    The real difference boils down to how much state the hardware has to flush in order to synchronize. Since a consume operation may therefore execute faster, someone who knows what they are doing can use it for performance critical applications.



    以下是我自己尝试更平凡的解释:

    另一种看待它的方法是从重新排序读取和写入的角度来看问题,包括原子的和普通的:

    全部 原子操作保证在它们自己内部是原子的(两个原子操作的组合作为一个整体不是原子的!)并且在它们出现在执行流的时间线上的总顺序中可见。这意味着在任何情况下都不能对原子操作进行重新排序,但其他内存操作很可能会重新排序。编译器(和 CPU)经常将重新排序作为优化。
    这也意味着编译器必须使用任何必要的指令来保证在任何时间执行的原子操作将看到每个其他原子操作的结果,可能在另一个处理器内核上(但不一定是其他操作),这些操作是之前执行的.

    现在,一个 轻松 就是这样,最低限度。它不做任何额外的事情,也不提供其他保证。这是最便宜的操作。对于强有序处理器架构(例如 x86/amd64)上的非读-修改-写操作,这归结为一个普通的普通移动。

    顺序一致 操作正好相反,它不仅对原子操作执行严格的排序,而且对发生在之前或之后的其他内存操作也执行严格的排序。任何人都无法跨越原子操作强加的障碍。实际上,这意味着失去优化机会,并且可能必须插入栅栏指令。这是最昂贵的模型。

    一个 发布 操作防止普通的加载和存储在原子操作之后被重新排序,而 获取 操作防止在原子操作之前对普通加载和存储进行重新排序。其他一切仍然可以移动。
    防止在相应的原子操作之后移动存储和在相应原子操作之前移动负载的组合确保获取线程看到的任何内容都是一致的,仅损失少量优化机会。
    人们可能会将其视为一种不存在的锁,它被(作者)释放并(被读者)获取。除了……没有锁。

    在实践中,释放/获取通常意味着编译器不需要使用任何特别昂贵的特殊指令,但它不能根据自己的喜好自由地重新排序加载和存储,这可能会错过一些(小的)优化机会。

    最后,消费 与获取相同的操作,只是排序保证仅适用于相关数据。相关数据将例如是由原子修改指针指向的数据。
    可以说,这可能提供了一些在获取操作中不存在的优化机会(因为较少的数据受到限制),但是这是以更复杂和更容易出错的代码为代价的,以及非平凡的任务获得正确的依赖链。

    当前不鼓励在修订规范时使用消费排序。

    关于c++ - 每个 memory_order 是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12346487/

    相关文章:

    c++ - 在功能上输入智能感知?

    c++ - 如何在 Tensorflow 的 c++ API 中使用复杂数据类型?

    c++ - 类的一部分互斥

    java - 这个java阻塞队列变体可能吗?

    ruby - 在(最新版本的)Ruby 中递增整数(使用 +=)线程安全吗?

    c++ - 操作全局静态变量

    c++ - 如何在编译时自动区分长短?

    .net - 不能在另一个项目的 dll 中使用一个类的 typedef

    c++ - 哪种持续集成工具最适合 C++ 项目?

    c++ - 如何扩展对可变参数模板基类的调用?