任何人都可以解释什么是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
Answers:
谁能用简单的英语解释什么是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 ++弱原子时,我不知道自己正在进入什么领域。它们背后的理论是如此复杂,以至于无法使用。花了三个人(安东尼,汉斯和我)和对标准的修改来完成相对简单算法的证明。想象一下,对于基于弱原子的无锁队列也是如此!
relaxed
更容易理解:仅在需要原子性而不需要同步时使用它。例如,对于单个原子计数器,多个线程将增加,但这对于其他任何数据是否有效没有任何意义。
这些std::memory_order
值使您可以对原子操作提供的内存顺序指定细粒度的约束。如果要从多个线程修改和访问原子变量,则将std::memory_order
值传递给您的操作将使您可以放宽对这些原子变量的操作对其他线程可见的顺序以及对同步的约束,以限制编译器和处理器的工作。这些操作对应用程序中非原子数据的影响。
的默认顺序std::memory_order_seq_cst
受最大约束,并提供您可能期望的“直观”属性:如果线程A存储了一些数据,然后使用设置了一个原子标志std::memory_order_seq_cst
,则如果线程B看到该标志已设置,那么它可以看到写入的数据其他内存排序值不一定提供此保证,因此必须非常谨慎地使用。
基本前提是:不要使用std::memory_order_seq_cst
(默认值)以外的任何东西,除非(a)您真的很了解自己在做什么,并且可以证明在所有情况下放松使用都是安全的,并且(b)您的探查器表明您打算使用宽松排序的数据结构和操作是一个瓶颈。
我的书《C ++并发性行动》一整章(45页)专门介绍C ++内存模型,原子操作和std::memory_order
约束的细节,另一章(44页)专门介绍了使用原子操作在无锁数据结构中进行同步。 ,以及放宽订购限制的后果。
我在有关Dekker算法和Peterson算法互斥的博客文章中展示了一些问题。
bool shouldHalt
要求线程停止。以我的经验,这种隔离在普通软件开发中并不罕见。我认为,对于其他情况(多个变量之间的依赖关系),锁首先总是总是更好。我看到人们对此有困难的唯一方法是使用奇特的原子链接数据结构,除非有必要,否则这是要提防的真实事物。
std::memory_order
在第5.2.1节中介绍后,您使用了许多不同的排序方式(甚至在解释它们在第5.3.3节中实际执行的操作之前),而不是遵循std::memory_order_seq_cst
此答案中的建议。这是否表示此答案(或书)不正确,还是我误解了?
std::memory_order_seq_cst
除非您真的知道自己在做什么,否则就应该坚持下去,这是一个行之有效的性能瓶颈。
简而言之,您的编译器和CPU可能会按与编写它们的方式不同的顺序执行指令。对于单线程,这不是问题,因为它将看起来正确。对于多个处理器上的多个线程,这成为一个问题。C ++中的内存排序限制了编译器/ CPU的功能,并解决了此类问题。
例如,如果您看一下我关于双重检查锁定的文章,您会发现排序如何与该模式混淆-它提到显示原子存储排序可用于修复它。
关于重新排序本身,您还可以考虑CPU重新排序-再次,编译器也可能会进行重新排序。
请注意,有关此主题的任何文档(包括我的文档)都提供了理论上的讲解。最常见的CPU(例如x86)具有非常强的排序保证,因此根本不需要很多显式排序。因此,即使您没有使用正确的C ++ 11原子,您的代码也可能仍然有效。
正如zvrba所述,该主题实际上非常详细。关于内存屏障的linux内核文档也包含很多详细信息。
在GCC Wiki中有一些普通的英语。;)