为啥原子操作需要独占缓存访问?

Posted

技术标签:

【中文标题】为啥原子操作需要独占缓存访问?【英文标题】:Why does atomic operation need exclusive cache access?为什么原子操作需要独占缓存访问? 【发布时间】:2019-03-09 09:03:21 【问题描述】:

在我的理解中原子操作(例如c++ atomic)首先锁定缓存行,然后执行原子操作。我有两个问题:1.如果说原子比较和交换是硬件中的原子操作本身,为什么我们需要锁定缓存线和2.当缓存线被锁定时,另一个cpu如何等待它?它使用自旋锁式等待吗?

谢谢

【问题讨论】:

你读过那个吗:fgiesen.wordpress.com/2014/08/18/atomics-and-contention 对于多核,原子更改必须对每个核生效。由于另一个核心可能已经缓存了相同的存储,它必须使存储无效以允许它“看到”更改。恕我直言,这是一个硬件问题,它是如何详细完成的。我不确定 C++ 是否与此相关(除了它确实提供 std::atomic 以允许访问该硬件功能(如果可用))。请注意std::atomic 可能会退回到其他锁定,如果 H/W 锁不适用于锁定类型。 std::atomic. 这种心智模型有点过于简单,无法真正取得进展,但处理器制造商将其内存控制器视为商业机密,因此您没有很多方法可以使其更准确。每个处理器都有一种使用特定指令集自动更新内存的方法。使用这些指令,这就是 std::atomic 所做的一切。当这样的更新正在进行时,其他内核肯定可以停止,你必须有点不走运。或者编写非最优代码。 我只是想知道为什么当原子操作本身对硬件来说是原子操作时需要独占缓存行访问...... 【参考方案1】:

首先:视情况而定!

1.) 如果系统锁定了缓存行,则与 c++ 无关。这是一个如何组织缓存的问题,尤其是汇编指令如何与缓存一起工作。这是cpu架构的问题!

2.) 编译器如何执行原子操作取决于实现。将生成哪些汇编程序指令来执行原子操作可能因编译器而异,甚至在不同版本上也可能不同。

3.) 据我所知,如果无法对访问相同缓存行的其他内核执行“更聪明”的通知/同步,则缓存行的完全锁定只是备用解决方案。但通常不仅涉及单个缓存。想想多级缓存架构。一些缓存只对单个核心可见!因此,还需要执行更多的内存系统操作作为锁定一条线。如果涉及多个内核,您还必须从不同的缓存级别移动数据!

4.) 从 c++ 的角度来看,原子操作不仅仅是单个操作。真正会发生什么取决于原子操作的内存排序选项。由于原子操作通常用于线程间同步,因此单个原子 RMW 操作必须做更多的事情!要了解所有必须做的事情,您应该给https://www.cplusplusconcurrencyinaction.com/ 一个机会。它详细介绍了内存屏障和内存排序。

5.) 锁定缓存行(如果确实发生这种情况)不应导致自旋锁或其他内核上的其他事情,因为对缓存行本身的访问只需要一些时钟周期。根据架构,它只是在某些周期内“持有”另一个核心。 “睡眠”核心可能会在不同的管道中并行执行其他操作。但是,嘿,这是非常特定于硬件的。

正如评论中已经给出的那样:看看https://fgiesen.wordpress.com/2014/08/18/atomics-and-contention/,它提供了一些提示,缓存一致性和锁定会发生什么。

不仅仅是在引擎盖下锁定。我相信你的问题只是表面问题!

实际使用:别想了!编译器供应商和 cpu 架构师做得非常好。作为程序员,您应该衡量您的代码性能。从我的角度来看:无需考虑如果缓存行被锁定会发生什么。您必须编写良好的算法并考虑程序数据的良好内存组织以及线程之间的较少相互关系。

【讨论】:

以上是关于为啥原子操作需要独占缓存访问?的主要内容,如果未能解决你的问题,请参考以下文章

volatile为啥不能保证原子性

原子操作成本

系统架构缓存Memcache 使用原子性操作add,实现并发锁

第四节:并发编程之Atomic&Unsafe魔法类

6.23Java多线程CAS原子操作

原子操作类原子操作的实现原理