问题描述
我读了一章,但我不太喜欢.我仍然不清楚每个内存顺序之间的区别.这是我目前的推测,在阅读了更简单的 http://en.cppreference.com/w/之后,我了解了cpp/atomic/memory_order
I read a chapter and I didn't like it much. I'm still unclear what the differences is between each memory order. This is my current speculation which I understood after reading the much more simple http://en.cppreference.com/w/cpp/atomic/memory_order
以下内容有误,请不要尝试学习
- memory_order_relaxed:不同步,但在不同原子变量中从另一种模式完成订单时不会被忽略
- memory_order_consume:同步读取此原子变量,但是不同步在此之前编写的宽松var.但是,如果线程在修改Y(并释放它)时使用varX.其他消耗Y的线程也会看到X释放吗?我不知道这是否意味着该线程推出了x(显然是y)的变化
- memory_order_acquire:同步读取此原子变量,并确保同步之前写入的宽松变量. (这是否意味着所有线程上的所有原子变量都已同步?)
- memory_order_release:将原子存储推送到其他线程(但前提是它们必须使用消耗/获取来读取var)
- memory_order_acq_rel:用于读取/写入操作.进行获取,以便您不修改旧值并释放更改.
- memory_order_seq_cst:与获取版本相同,不同之处在于它强制将更新显示在其他线程中(如果
a
宽松地存储在另一个线程上.我将b
与seq_cst存储在一起.第三个线程读取a
与放松会看到与b
和任何其他原子变量一起发生的变化?).
- memory_order_relaxed: Does not sync but is not ignored when order is done from another mode in a different atomic var
- memory_order_consume: Syncs reading this atomic variable however It doesnt sync relaxed vars written before this. However if the thread uses var X when modifying Y (and releases it). Other threads consuming Y will see X released as well? I don't know if this means this thread pushes out changes of x (and obviously y)
- memory_order_acquire: Syncs reading this atomic variable AND makes sure relaxed vars written before this are synced as well. (does this mean all atomic variables on all threads are synced?)
- memory_order_release: Pushes the atomic store to other threads (but only if they read the var with consume/acquire)
- memory_order_acq_rel: For read/write ops. Does an acquire so you don't modify an old value and releases the changes.
- memory_order_seq_cst: The same thing as acquire release except it forces the updates to be seen in other threads (if
a
store with relaxed on another thread. I storeb
with seq_cst. A 3rd thread readinga
with relax will see changes along withb
and any other atomic variable?).
我认为我理解了,但如果我做错了,请纠正我.我找不到任何能以通俗易懂的英语来解释它的东西.
I think I understood but correct me if i am wrong. I couldn't find anything that explains it in easy to read english.
推荐答案
GCC Wiki提供了非常彻底且易于理解的解释和代码示例.
The GCC Wiki gives a very thorough and easy to understand explanation with code examples.
(摘录已编辑,并已强调)
(excerpt edited, and emphasis added)
在将我自己的措辞添加到答案的过程中,重新阅读了从GCC Wiki复制来的以下引用后,我注意到该引用实际上是错误的.他们 acquire 和 consume 完全错误. release-consume 操作仅提供对相关数据的排序保证,而 release-acquire 操作则提供该保证,而不管数据是否依赖于原子值.
Upon re-reading the below quote copied from the GCC Wiki in the process of adding my own wording to the answer, I noticed that the quote is actually wrong. They got acquire and consume exactly the wrong way around. A release-consume operation only provides an ordering guarantee on dependent data whereas a release-acquire operation provides that guarantee regardless of data being dependent on the atomic value or not.
相反的方法是memory_order_relaxed
.通过消除事前发生的限制,该模型允许少得多的同步.这些类型的原子操作也可以对其执行各种优化,例如死存储的删除和通用. [...]没有任何事情发生-在边缘之前,没有线程可以依靠另一个线程的特定顺序.
放松模式是最常用于程序员仅希望变量本质上是原子的,而不是使用它来同步其他共享内存数据的线程的情况.
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.
第三种模式(memory_order_acquire
/memory_order_release
)是其他两种模式之间的混合.获取/释放模式与顺序一致模式类似,不同之处在于它仅将先发生后关系应用于因变量.这允许放宽独立写入的独立读取之间所需的同步.
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
是对发布/获取内存模型的进一步细化改进,它通过在对非因变量进行排序之前也消除了发生的情况,从而稍微放松了需求..
[...]
真正的差异归结为硬件必须刷新多少状态才能进行同步.由于消耗操作 可能执行得更快,因此知道自己在做什么的人可以将其用于对性能有严格要求的应用程序.
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.
以下是我自己对一个平凡的解释的尝试:
一种不同的查看方法是从重新排列原子和普通读写的角度来看问题:
Here follows my own attempt at a more mundane explanation:
A different approach to look at it is to look at the problem from the point of view of reordering reads and writes, both atomic and ordinary:
所有原子操作都必须在自己内部是原子的(两个原子操作的组合不是一个整体的原子!)并且在总顺序中可见它们出现在执行流的时间轴上.这意味着在任何情况下都无法对原子操作进行重新排序,而其他内存操作则可能会重新排序.编译器(和CPU)通常会进行诸如优化之类的重新排序.
这也意味着编译器必须使用任何必要的指令,以确保在任何时候执行的原子操作都可以看到在此之前执行的每个其他原子操作的结果,可能在另一个处理器内核上(但不一定是其他操作).
All atomic operations are guaranteed to be atomic within themselves (the combination of two atomic operations is not atomic as a whole!) and to be visible in the total order in which they appear on the timeline of the execution stream. That means no atomic operation can, under any circumstances, be reordered, but other memory operations might very well be. Compilers (and CPUs) routinely do such reordering as an optimization.
It also means the compiler must use whatever instructions are necessary to guarantee that an atomic operation executing at any time will see the results of each and every other atomic operation, possibly on another processor core (but not necessarily other operations), that were executed before.
现在,放松就是最低要求.它没有做任何其他事情,并且不提供其他任何保证.这是最便宜的操作.对于在严格排序的处理器体系结构(例如x86/amd64)上进行的非读取-修改-写入操作,这可以归结为普通,普通的举动.
Now, a relaxed is just that, the bare minimum. It does nothing in addition and provides no other guarantees. It is the cheapest possible operation. For non-read-modify-write operations on strongly ordered processor architectures (e.g. x86/amd64) this boils down to a plain normal, ordinary move.
顺序一致操作正好相反,它不仅对原子操作,而且对之前或之后发生的其他内存操作都执行严格的排序.任何人都无法越过原子操作施加的障碍.实际上,这意味着失去了优化机会,并且可能必须插入围栏指令.这是最昂贵的模型.
The sequentially consistent operation is the exact opposite, it enforces strict ordering not only for atomic operations, but also for other memory operations that happen before or after. Neither one can cross the barrier imposed by the atomic operation. Practically, this means lost optimization opportunities, and possibly fence instructions may have to be inserted. This is the most expensive model.
释放操作可防止在原子操作之后 对普通负载和存储进行重新排序,而 acquire 操作可防止普通负载和存储在原子操作之后重新排序.在原子操作之前之前被重新排序.其他所有内容仍然可以移动.
阻止存储在相应的原子操作之后移动以及负载在相应的原子操作之前移动的组合确保了获取线程看到的内容是一致的,仅损失了少量的优化机会.
有人可能会认为这是一种不存在的锁,它正在(由作者)释放并由(读者)获取.除了...没有锁.
A release operation prevents ordinary loads and stores from being reordered after the atomic operation, whereas an acquire operation prevents ordinary loads and stores from being reordered before the atomic operation. Everything else can still be moved around.
The combination of preventing stores being moved after, and loads being moved before the respective atomic operation makes sure that whatever the acquiring thread gets to see is consistent, with only a small amount of optimization opportunity lost.
One may think of that as something like a non-existent lock that is being released (by the writer) and acquired (by the reader). Except... there is no lock.
在实践中,发布/获取通常意味着编译器不需要使用任何特别昂贵的特殊指令,但是它不能自由地对加载和存储进行重新排序,这可能会错过一些(小的)优化机会.
In practice, release/acquire usually means the compiler needs not use any particularly expensive special instructions, but it cannot freely reorder loads and stores to its liking, which may miss out some (small) optimization opportuntities.
最后,消费与 acquire 相同,只是顺序保证仅适用于相关数据.相关数据例如是原子修改后的指针指向的数据.
可以说,这可能会提供一些购置操作不存在的优化机会(因为较少的数据受到限制),但这是以更复杂,更容易出错的代码以及非平凡的任务为代价的正确实现依赖关系链的方法.
Finally, consume is the same operation as acquire, only with the exception that the ordering guarantees only apply to dependent data. Dependent data would e.g. be data that is pointed-to by an atomically modified pointer.
Arguably, that may provide for a couple of optimization opportunities that are not present with acquire operations (since fewer data is subject to restrictions), however this happens at the expense of more complex and more error-prone code, and the non-trivial task of getting dependency chains correct.
目前不建议在修订规范时使用 consumption 排序.
It is currently discouraged to use consume ordering while the specification is being revised.
这篇关于每个memory_order是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!