C++ 比较并交换C++;0x
添加新的子条款,包括以下段落 枚举C++ 比较并交换C++;0x,c++,multithreading,gcc,compare-and-swap,stdatomic,C++,Multithreading,Gcc,Compare And Swap,Stdatomic,添加新的子条款,包括以下段落 枚举内存\u顺序指定了详细的常规(非原子)内存同步顺序,如[N2334添加的新部分或其采用的后续部分]中所定义,并可提供操作顺序。其列举值及其含义如下 memory\u order\u released 该操作不会对内存进行排序 memory\u order\u release 对受影响的内存位置执行释放操作,从而使常规内存写入通过应用它的原子变量对其他线程可见 memory\u order\u acquire 对受影响的内存位置执行获取操作,从而使通过
内存\u顺序
指定了详细的常规(非原子)内存同步顺序,如[N2334添加的新部分或其采用的后续部分]中所定义,并可提供操作顺序。其列举值及其含义如下
memory\u order\u released
memory\u order\u release
memory\u order\u acquire
memory\u order\u acq\u rel
memory\u order\u seq\u cst
我的理解是“
memory\u order\u acq\u rel
”只需要同步操作所需的内存位置,而其他内存位置可能保持不同步(它不会充当内存围栏)
现在,我的问题是-如果我选择“memory\u order\u acq\u rel
”并将compare\u swap
应用于整数类型,例如整数,在现代消费类处理器(如多核Intel i7)上,这通常如何转换为机器代码?其他常用的体系结构(x64、SPARC、ppc、arm)如何
特别是(假设是一个具体的编译器,比如gcc):
acq\u rel
语义是否有任何性能优势?其他架构呢谢谢所有的答案。这里的答案并不琐碎。究竟发生了什么,意味着什么,取决于很多事情。对于缓存一致性/内存的基本理解,我最近的博客可能会有所帮助:
compare_swap( C& expected, C desired,
memory_order success, memory_order failure )
架构不可能完全按照您的要求实现这一点;许多人将不得不将其强化到足够强大的程度,以便能够实施。当您指定内存顺序时,您是在指定重新排序的工作方式。要使用英特尔的术语,您需要指定所需的防护栏类型,共有三种:完整防护栏、加载防护栏和存储防护栏。(但在x86上,load fence和store fence仅对NT stores之类的弱顺序指令有用;atomics不使用它们。常规的load/store为您提供了所有功能,但在以后加载后可能出现的存储除外。)仅仅因为您希望在该操作上使用特定的fence并不意味着它受支持,我希望它总是回到一个完整的围栏。(请参阅有关内存屏障的信息)
不管内存顺序如何,x86(包括x64)编译器都可能使用该指令来实现CAS。这意味着一个完整的障碍;x86无法在没有锁定
前缀的情况下访问,这也是一个完整的障碍。纯存储和纯加载可以“自行”实现原子化,因为许多ISA需要为上述任何内容设置障碍
此指令是无锁的,尽管所有尝试CAS相同位置的内核都会争夺对它的访问权,因此您可能会认为它不是真正的无等待。(使用它的算法可能不是无锁的,但操作本身是无等待的,)。在非x86上,使用而不是锁定
ed指令时,通常无需等待,但比较交换(compare)强
需要重试循环以防出现错误
现在C++11已经存在多年了,您可以查看各种体系结构的asm输出
在内存同步方面,你需要了解缓存一致性是如何工作的(我的博客可能会有所帮助)。新的CPU使用ccNUMA体系结构(以前是SMP)。实际上,内存上的“视图”永远不会失去同步。代码中使用的围栏实际上并不强制缓存本身发生任何刷新,只强制存储缓冲区在稍后加载之前将飞行中的存储提交到缓存 如果两个核心都在缓存线中缓存了相同的内存位置,则一个核心的存储将获得缓存线的独占所有权(使所有其他副本无效),并将其自身标记为脏。一个非常复杂的过程的非常简单的解释 要回答上一个问题,您应该始终使用逻辑上需要正确的内存语义。大多数体系结构不支持您在程序中使用的所有组合。然而,在许多情况下,您会得到很好的优化,特别是在
compare_swap( C& expected, C desired,
memory_order success, memory_order failure )