其他分享
首页 > 其他分享> > c – 每个memory_order是什么意思?

c – 每个memory_order是什么意思?

作者:互联网

我读了一章,我不喜欢它.我还不清楚每个内存顺序之间的差异.这是我目前的推测,我在阅读了更为简单的http://en.cppreference.com/w/cpp/atomic/memory_order之后就明白了

以下是错误的,所以不要试图从中学习

> memory_order_relaxed:当从另一个原子var中的另一个模式完成订单时,不同步但不会被忽略
> memory_order_consume:Syncs读取这个原子变量然而它没有同步在此之前写的轻松变量.但是,如果线程在修改Y(并释放它)时使用var X.消耗Y的其他线程也将看到X发布?我不知道这是否意味着这个线程推出了x的变化(显然是y)
> memory_order_acquire:同步读取此原子变量并确保在此之前写入的轻松变量也同步. (这是否意味着所有线程上的所有原子变量都被同步?)
> memory_order_release:将原子存储推送到其他线程(但只有当他们使用consume / acquire读取var时)
> memory_order_acq_rel:用于读/写操作.获取是否因此您不修改旧值并释放更改.
> memory_order_seq_cst:与获取版本相同的东西,除了它强制在其他线程中看到更新(如果在另一个线程上放松的商店.我用seq_cst存储b.第三个线程读取带有relax的将看到变化以及b和任何其他原子变量?).

如果我错了,我想我理解但是纠正我.我找不到任何用易于阅读的英语解释它的东西.

解决方法:

GCC Wiki为very thorough and easy to understand explanation提供了代码示例.

(摘录编辑,重点补充)

重要:

在重新阅读从GCC Wiki复制的以下引用的过程中,我将自己的措辞添加到答案中,我注意到引用实际上是错误的.他们获得并以完全错误的方式消费.释放 – 消耗操作仅提供依赖数据的排序保证,而释放 – 获取操作提供该保证,而不管数据是否依赖于原子值.

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)上的非读取 – 修改 – 写入操作,这归结为普通的普通移动.

顺序一致的操作恰恰相反,它不仅对原子操作强制执行严格的排序,而且对在之前或之后发生的其他存储器操作强制执行.两者都不能跨越原子操作所施加的障碍.实际上,这意味着失去了优化机会,并且可能必须插入围栏指令.这是最昂贵的型号.

释放操作防止普通加载和存储在原子操作之后被重新排序,而获取操作防止普通加载和存储在原子操作之前被重新排序.其他所有东西仍然可以移动.
防止在之后移动存储以及在相应的原子操作之前移动加载的组合确保获取线程看到的任何内容是一致的,仅丢失少量优化机会.
人们可能会认为这就像是一个不存在的锁(由作者发布)并被(由读者获得)获得.除了……没有锁.

在实践中,发布/获取通常意味着编译器不需要使用任何特别昂贵的特殊指令,但它不能自由地对负载和存储进行重新排序,这可能会错过一些(小的)优化机会.

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

目前不鼓励在修改规范时使用消费排序.

标签:memory-model,c,c11,thread-safety,atomic
来源: https://codeday.me/bug/20190925/1817211.html