谁能解释一下std::memory_order
简单的英语是什么,以及如何使用它们std::atomic<>
?
我在这里找到了参考资料和几个例子,但根本不明白。 http://en.cppreference.com/w/cpp/atomic/memory_order
谁能解释一下std::memory_order
简单的英语是什么,以及如何使用它们std::atomic<>
?
我在这里找到了参考资料和几个例子,但根本不明白。 http://en.cppreference.com/w/cpp/atomic/memory_order
这些std::memory_order
值允许您对原子操作提供的内存排序指定细粒度的约束。如果您正在从多个线程修改和访问原子变量,那么将std::memory_order
值传递给您的操作允许您放松对编译器和处理器的约束,即这些原子变量上的操作对其他线程可见的顺序以及同步这些操作对应用程序中的非原子数据的影响。
的默认排序std::memory_order_seq_cst
是最受约束的,并提供您可能期望的“直观”属性:如果线程 A 存储一些数据,然后使用 设置原子标志std::memory_order_seq_cst
,那么如果线程 B 看到设置了标志,那么它可以看到写入的数据由线程 A. 其他内存排序值不一定提供此保证,因此必须非常小心地使用。
基本前提是:不要使用std::memory_order_seq_cst
(默认)以外的任何东西,除非(a)你真的知道你在做什么,并且可以证明轻松的使用在所有情况下都是安全的,并且(b)你的分析器证明了您打算使用宽松排序的数据结构和操作是一个瓶颈。
我的书C++ Concurrency in Action用一整章(45 页)详细介绍了 C++ 内存模型、原子操作和std::memory_order
约束,还有一章(44 页)用于在无锁数据结构中使用原子操作进行同步,以及放宽排序约束的后果。
我关于Dekker 算法和Peterson互斥算法的博客文章展示了一些问题。
谁能用简单的英语解释什么是 std::memory_order ,
我为各种内存排序找到的最好的“简单英语”解释是 Bartoz Milewski 关于轻松原子的文章:http: //bartoszmilewski.com/2008/12/01/c-atomics-and-memory-ordering/
以及后续帖子:http ://bartoszmilewski.com/2008/12/23/the-inscrutable-c-memory-model/
但请注意,虽然这些文章是一个很好的介绍,但它们早于 C++11 标准,并且不会告诉您安全使用它们所需知道的一切。
以及如何将它们与 std::atomic<> 一起使用?
我在这里给你的最好建议是:不要。宽松的原子(可能)是 C++11 中最棘手和最危险的事情。坚持std::atomic<T>
使用默认的内存排序(顺序一致性),直到你真的非常确定你有一个可以通过使用宽松的内存排序来解决的性能问题。
在上面链接的第二篇文章中,Bartoz Milewski 得出以下结论:
在尝试推理 C++ 弱原子时,我不知道自己会陷入什么困境。它们背后的理论是如此复杂,以至于它几乎无法使用。花了三个人(安东尼、汉斯和我)和对标准的修改来完成一个相对简单的算法的证明。想象一下对基于弱原子的无锁队列做同样的事情!
没有。“简单的英语”解释需要 32 页,可以在这里找到。
如果您不想阅读,您可以忘记内存排序,因为您链接到的页面说默认是顺序一致的排序,这是“总是做理智的事情”设置。
要使用任何其他设置,您必须阅读并理解上述论文及其中的示例。
简而言之,您的编译器和 CPU 执行指令的顺序可能与您编写它们的顺序不同。对于单线程,这不是问题,因为它看起来是正确的。对于多个处理器上的多个线程,这成为一个问题。C++ 中的内存排序限制了您的编译器/CPU 可以执行的操作并修复了此类问题。
例如,如果您查看我关于双重检查锁定的文章,您会看到排序与该模式是如何混淆的——它提到可以使用显示原子内存排序来修复它。
关于重新排序本身,您还可以考虑CPU 重新排序——同样,编译器也可能也在进行重新排序。
请注意,有关此主题的任何文档(包括我的)都提供了理论场景。最常见的 CPU,如 x86,具有非常强大的排序保证,因此根本不需要大量显式排序。因此,即使您不使用正确的 C++11 原子,您的代码也可能仍然有效。
正如 zvrba 提到的,这个话题实际上是相当详细的。关于内存屏障的 linux 内核文档也包含很多详细信息。
GCC wiki 中有一些简单的英语。;)