gpt4 book ai didi

c++ - 比较并交换C++ 0x

转载 作者:IT老高 更新时间:2023-10-28 22:22:05 25 4
gpt4 key购买 nike

从关于C++原子类型和操作的C++0x proposal中:

29.1 Order and Consistency [atomics.order]

Add a new sub-clause with the following paragraphs.

The enumeration memory_order specifies the detailed regular (non-atomic) memory synchronization order as defined in [the new section added by N2334 or its adopted successor] and may provide for operation ordering. Its enumerated values and their meanings are as follows.

  • memory_order_relaxed

The operation does not order memory.

  • memory_order_release

Performs a release operation on the affected memory locations, thus making regular memory writes visible to other threads through the atomic variable to which it is applied.

  • memory_order_acquire

Performs an acquire operation on the affected memory locations, thus making regular memory writes in other threads released through the atomic variable to which it is applied, visible to the current thread.

  • memory_order_acq_rel

The operation has both acquire and release semantics.

  • memory_order_seq_cst

The operation has both acquire and release semantics, and in addition, has sequentially-consistent operation ordering.



在提案中降低:

bool A::compare_swap( C& expected, C desired,
memory_order success, memory_order failure ) volatile

where one can specify memory order for the CAS.



我的理解是,“ memory_order_acq_rel”仅会同步操作所需的那些内存位置,而其他内存位置可能保持不同步(它不会充当内存围栏)。

现在,我的问题是-如果我选择“ memory_order_acq_rel”并将 compare_swap应用于整数等整数类型,那么在现代消费类处理器(例如多核Intel i7)上,这通常如何转换为机器代码?其他常用架构(x64,SPARC,ppc,arm)又如何呢?

特别是(假设一个具体的编译器,例如gcc):
  • 如何通过上述操作比较并交换整数位置?
  • 这样的代码会产生什么指令序列?
  • 该操作在i7上是无锁的吗?
  • 这样的操作是否可以运行完整的缓存一致性协议(protocol),从而像i7上的内存栅栏一样同步不同处理器核心的缓存?还是只是同步此操作所需的内存位置?
  • 与上一个问题有关-在i7上使用acq_rel语义是否有性能优势?那么其他架构呢?

  • 感谢所有的答案。

    最佳答案

    答案并不简单。到底发生了什么,意味着什么取决于许多事情。为了基本了解缓存的一致性/内存,也许我最近的博客文章可能会有所帮助:

  • CPU Reordering – What is actually being reordered?
  • CPU Memory – Why do I need a mutex?

  • 除此之外,让我尝试回答几个问题。首先,下面的功能对支持的功能很有希望:对内存顺序保证的强度进行非常细粒度的控制。这对于编译时重新排序是合理的,但对于运行时障碍通常不是。
    compare_swap( C& expected, C desired,
    memory_order success, memory_order failure )

    架构将无法完全按照您的要求来实现。许多人将不得不将其增强到足以实现的强大功能。当您指定memory_order时,您将指定重新排序的工作方式。要使用英特尔的术语,您将指定所需的围栏类型,其中有三种,全围栏,装载围栏和商店围栏。 (但是在x86上,加载围栏和存储围栏仅对诸如NT存储之类的顺序较弱的指令有用;原子不会使用它们。常规加载/存储会为您提供一切,除了存储可以在以后的加载之后出现。)在该操作上使用特定的栅栏并不意味着会予以支持,我希望它始终会退回到完整的栅栏上。 (有关内存障碍,请参见 Preshing's article)

    x86(包括x64)编译器可能会使用 LOCK CMPXCHG 指令来实现CAS,而与内存顺序无关。这意味着完全的障碍; x86没有没有 lock前缀的方法无法到达 make a read-modify-write operation atomic,这也是一个障碍。 pure-store和pure-load可以是原子上的“独立”,许多ISA对于 mo_relaxed以外的任何事物都需要障碍,但 x86 does acq_rel "for free" in asm除外。

    该指令是无锁的,尽管试图将CAS置于同一位置的所有内核都将争夺对它的访问权,所以您可以说它并不是真正的无锁。 (使用它的算法可能不是无锁的,但操作本身是无等待的 see wikipedia's non-blocking algorithm article)。在使用 LL/SC而不是 lock ed指令的非x86上, C++11 compare_exchange_weak 通常无需等待,但 compare_exchange_strong在假性失败的情况下需要重试循环。

    既然C++ 11已经存在多年了,您可以查看各种体系结构 on the Godbolt compiler explorer的asm输出。

    在内存同步方面,您需要了解缓存一致性的工作原理(我的博客可能会有所帮助)。新的CPU使用ccNUMA架构(以前为SMP)。本质上,内存上的“ View ”永远不会变得不同步。代码中使用的隔离实际上并没有强制缓存本身发生任何刷新,只有在飞行商店中提交的存储缓冲区在以后加载之前才进行缓存。

    如果两个内核在缓存行中缓存的内存位置相同,则由一个内核进行的存储将获得缓存行的独占所有权(使所有其他拷贝无效)并将其自身标记为脏。对于非常复杂的过程的非常简单的解释

    要回答您的最后一个问题,您应该始终使用逻辑上必须正确的内存语义。大多数体系结构不支持您在程序中使用的所有组合。但是,在许多情况下,您会获得很好的优化,尤其是在保证所要求的订单没有栅栏的情况下(这是很常见的)。

    -对一些评论的回答:

    您必须区分执行写指令和写入存储位置的含义。这就是我试图在博客文章中解释的内容。到“0”提交到0x100时,所有内核都看到该零。写入整数也是原子的,即使没有锁也是如此,当您写入一个位置时,如果所有内核都希望使用它,它将立即具有该值。

    麻烦的是,要使用您可能已先将其加载到寄存器中的值,此后对位置的任何更改显然都不会触及寄存器。这就是为什么尽管有高速缓存一致性内存也需要互斥或 atomic<T>的原因:允许编译器将纯变量值保留在专用寄存器中。 (在C++ 11中,这是因为对非 atomic变量的数据争用是未定义的行为。)

    关于矛盾的主张,通常您会看到各种各样的主张。它们是否矛盾归结为上下文中“看到”,“加载”,“执行”的确切含义。如果将“1”写入0x100,是否意味着您执行了写指令或CPU实际提交了该值。由存储缓冲区创建的差异是重新排序的主要原因之一(只有一个x86允许)。 CPU可以延迟写入“1”,但是您可以确定,当它最终提交“1”时,所有内核都可以看到它。围墙通过使线程等到存储区提交后再执行后续操作来控制此顺序。

    关于c++ - 比较并交换C++ 0x,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4213523/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com