比较和交换C ++ 0x

问题描述 投票:16回答:2

从C ++原子类型和操作的C++0x proposal

29.1顺序和一致性[atomics.order]

用以下段落添加新的子句。

枚举memory_order指定了详细的常规(非原子)内存同步顺序,如[由N2334或其后继产品添加的新部分]中所定义,并且可以提供操作顺序。其枚举值及其含义如下。

  • memory_order_relaxed

该操作不订购内存。

  • memory_order_release

在受影响的内存位置执行释放操作,从而使常规内存写操作通过应用该对象的原子变量对其他线程可见。

  • memory_order_acquire

在受影响的内存位置上执行获取操作,从而使其他线程通过对其应用了原子变量释放的其他线程中的常规内存写操作对当前线程可见。

  • memory_order_acq_rel

该操作同时具有获取和释放语义。

  • memory_order_seq_cst

该操作具有获取和释放语义,此外,还具有顺序一致的操作顺序。

在提案中降低:

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

其中可以指定CAS的存储顺序。


[我的理解是,[memory_order_acq_rel]只需要同步操作所需的那些存储位置,而其他存储位置可能保持不同步(它不会充当存储屏障)。

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

特别是(假设使用具体的编译器,例如gcc):

  1. 如何通过上述操作比较并交换整数位置?
  2. 这样的代码将产生什么指令序列?
  3. i7上的操作是否处于锁定状态吗?
  4. 这样的操作是否将运行完整的缓存一致性协议,从而像i7上的内存屏障一样同步不同处理器核心的缓存?还是仅同步此操作所需的内存位置?
  5. 与先前的问题有关-在i7上使用acq_rel语义是否有性能优势?那其他架构呢?

感谢所有答案。

c++ multithreading gcc concurrency compare-and-swap
2个回答
7
投票

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

但是除此之外,让我尝试回答一些问题。首先,下面的说明对所支持的内容很有希望。

compare_swap( C& expected, C desired,
        memory_order success, memory_order failure )

架构无法完全按照您的要求实施。当您指定memory_order时,您将指定重新排序的工作方式。要使用intel的术语,您将指定所需的栅栏类型,其中有三种,全栅栏,负载栅栏和商店栅栏。仅仅因为您希望该操作上有特定的防护范围并不意味着会支持它,所以我希望它总是退回到完整的防护范围内。

编译器可能会使用CMPXCHG指令来实现该调用。如果您指定的内容不是松弛的,它将用lock进行标记,以表明该功能应该是原子的。是否“无锁”在很大程度上取决于您对“锁”的考虑。

关于内存同步,您需要了解缓存一致性的工作原理(我的博客可能会有所帮助)。新的CPU使用ccNUMA架构(以前为SMP)。本质上,内存上的“视图”永不同步。代码中使用的围栏实际上并没有强制冲洗本身。如果两个内核在高速缓存行中具有相同的内存位置,则其中一个将被标记为脏,而另一个将在必要时重新加载。 对非常复杂的过程的非常简单的解释

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

-对一些评论的回答:

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

麻烦的是,要使用您可能先将其加载到寄存器中的值,此后对位置的任何更改显然都不会触及寄存器。这就是为什么尽管有缓存一致性内存也需要互斥的原因。

关于矛盾的主张,通常您会看到各种各样的主张。它们是否矛盾归结为上下文中“看到”,“加载”,“执行”的确切含义。如果将“ 1”写入0x100,是否意味着您执行了写指令或CPU实际提交了该值。区别来自重新排序。 CPU可以延迟写入“ 1”,但是您可以确定,当它最终提交“ 1”时,所有内核都可以看到它。围栏控制此顺序。


0
投票

您的整个世界观似乎不合时宜:您的问题暗示高速缓存一致性由C ++级别的内存顺序和CPU级别的篱笆或原子操作控制。

但是高速缓存一致性是物理体系结构最重要的不变性之一,它由存储系统始终提供,该存储系统由所有CPU和RAM的互连组成。您永远无法从运行在CPU上的代码中击败它,甚至无法看到其操作细节。当然,通过直接观察RAM并在其他地方运行代码,您可能会在某些内存级别上看到过时的数据:根据定义,RAM并不是所有内存位置的最新值。但是在CPU上运行的代码无法访问RAM,只能访问一致的抽象内存。

因此问题仅存在于外部设备。

这样的操作将运行完整的缓存一致性协议,同步不同处理器核心的缓存,就好像它是一个i7上的内存栅栏?

它们已经同步。

或者它只是同步存储位置该操作需要吗?

原子操作仅适用于一个内存位置。您还要考虑其他哪些位置?

© www.soinside.com 2019 - 2024. All rights reserved.