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
该操作既有获取语义又有释放语义,此外,还具有顺序一致的操作顺序

建议中较低的部分:

其中可以指定CAS的内存顺序


我的理解是“
memory\u order\u acq\u rel
”只需要同步操作所需的内存位置,而其他内存位置可能保持不同步(它不会充当内存围栏)

现在,我的问题是-如果我选择“
memory\u order\u acq\u rel
”并将
compare\u swap
应用于整数类型,例如整数,在现代消费类处理器(如多核Intel i7)上,这通常如何转换为机器代码?其他常用的体系结构(x64、SPARC、ppc、arm)如何

特别是(假设是一个具体的编译器,比如gcc):

  • 如何将整数位置与上述操作进行比较和交换
  • 这样的代码将产生什么指令序列
  • i7上的操作锁是否可用
  • 这样的操作会运行完全缓存一致性协议,同步不同处理器内核的缓存,就像它是i7上的内存围栏一样吗?或者它只是同步此操作所需的内存位置
  • 与前面的问题相关-在i7上使用
    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 )