CPU实现原子操作的原理
586之前的CPU, 会通过LOCK锁总线的形式来实现原子操作. 686开始则提供了存储一致性(Cache coherence), 这是多处理的基础, 也是原子操作的基础.
1. 存储的粒度
存储的组织形式(粒度)是以CacheLine为单位的, 通常为64字节甚至更高(早期也有32字节的). 然后几组CacheLine组成一个小的LRU(或者其他替换规则).
2. 协议
存储一致性(CC)一般是通过MESI协议, 以及后续的变种协议, 例如Intel的MESIF协议和AMD的MOESI协议, 来实现的.
以MESI协议为例:
Modified: 独占CacheLine, 已经修改了, 但是还未同步到主存
Exclusive: 独占, 并且和主存一致
Shared : 共享的, 其他core也拥有该CacheLine, 并且与主存中一致
Invalid: 表示该CacheLine不可用
3. 通讯
有了协议, 那么就需要通讯来实现协议(存储的状态). 通讯有两种, 一种是广播/侦听, 一种是目录式.
广播/侦听顾名思义就是存储状态的变更, 会被广播到其他core上面去, 进而去维护CacheLine的状态. 很明显这种方式会浪费大量的流量, 而且难以扩展, CPU核数多了, 总线就是明显的瓶颈.
目录式, 就是把改变通知给具体的core, 从而避免广播. 但是考虑一种极端情况, 如果很多个core都在访问同一个CacheLine, 那还是不能避免(事实上的)广播. 所以, 多线程编程时, 共享同一个CacheLine不是一个好的选择.
有了上面的东西, 现在我们来考虑原子操作的实现:
1. 原子的Load/Store
由于CPU对缓存的管理是以CacheLine为单位的, 所以在一个CacheLine内load/store实际上都是原子的. Load和Store一个8字节对象, 不可能高4位和低4位是分开操作的(从而搞成俩值).
但是光有这个实际上还不够, CPU对CacheLine的修改不是立即写到主存里面去, 所以其他Core看到的值就有可能是老的值, 所以这时候还需要fence来读到最新的值; 至于写, 那一定需要写权限, 即M或者E状态, 而这两个权限里面都有最新的值(只是你刚才读到的不一定是最新的, 所以有可能用老值覆盖了新值).
2. FetchAndAdd
这是比load和store稍微复杂的操作, 实际上是一个复合操作. 但是有了M和E状态, 就很好理解了:
- lock(CacheLine)
- v := load(obj)
- v += add
- store(obj, v)
- release(CacheLine)
x86里面是xadd指令.
3. CompareAndSwap
那么CAS, 也就可以猜出来:
- lock(CacheLine)
- v := load(obj)
- if v != expected {
- store(obj, new_value)
- }
- release(CacheLine)
x86里面是xchg
这里说的lock和release均表示对该CacheLine独占和解出独占的意思.
关于原子操作的原理, 鲜有资料表表示其具体怎么做的, 很有可能是过于偏向于硬件. 但是对MESI等协议的思考, 实际上还是能猜到CPU内部的实现(至少七八不离十). 好在找到两个资料, 一个是<<并行多核体系结构基础>>和<<从鲲鹏920了解现代服务器实现和引用>>. 其中鲲鹏920内存模型章节这么写到:
原子指令在软件上看来逻辑并不复杂,但在微架构上看,成本是很高的。如果我们把CPU 和内存都看做是总线上的一个个独立的实体,有一个CPU要做CAS指令,这个CPU需要先从 内存中读一个值,同时要在内存控制器上设置一个标志,保证其他CPU写不进去,等它比 较完了,然后再决定写一个值回去,才会让其他CPU写入。
不同微架构实现有不同方法对行为进行优化,在鲲鹏920上,原子指令的请求需要在 L3Cache上进行排队,保证在原子操作的多个动作之间能维持原子指令要求的语义。这个 排队本身也有成本。所以没有原子需要就不要轻易用原子变量,这其实是有成本的。
并行多核体系结构这么写到:
幸运的是, 缓存一致性协议提供了原子性被保障的基础. 举例来说, 当遇到一个原子指令时, 这个协议知道需要保证原子性. 他首先获得对存储单元M的"独家所有权" (通过将其他包含M的缓存块中的拷贝都置为无效). 当获得独家所有权之后, 这个协议会确保只有一个处理器能够访问这个块, 而如果其他处理器在此时想要访问的话就会经历缓存缺失, 接下来原子指令就可以执行. 在原子指令持续期间, 其他处理器不允许"偷走"这个块. 距离来说, 如通另一个处理器要求读或者写这个块, 这个块就被"偷"了(如块被清理, 块的状态被降级为无效). 在原子指令完成之前暴露块会破坏指令的原子性, ......
参考:
1) 并行多核体系结构基础
CPU实现原子操作的原理的更多相关文章
- 代码中理解CPU结构及工作原理
一.前言 从研究生开始到工作半年,陆续在接触MCU SOC这些以CPU为核心的控制器,但由于专业的原因一直对CPU的内部结构和工作原理一知半解.今天从一篇博客中打破一直以来的盲区.特此声明,本文设计思 ...
- 1、cpu架构和工作原理
cpu架构和工作原理 计算机有5大基本组成部分,运算器,控制器,存储器,输入和输出.运算器和控制器封装到一起,加上寄存器组和cpu内部总线构成中央处理器(CPU).cpu的根本任务,就是执行指令,对计 ...
- CPU GPU设计工作原理《转》
我知道这非常长,可是,我坚持看完了.希望有幸看到这文章并对图形方面有兴趣的朋友,也能坚持看完.一定大有收获.毕竟知道它们究竟是怎么"私下勾搭"的.会有利于我们用程序来指挥它们... ...
- CPU内部组成及原理
CPU,Central Processing Unit,翻译过来叫中央处理器.是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit).电脑中所有操作都由C ...
- CPU中断的工作原理,从最底层讲起
前言 中断的概念属于硬件层.虽然我们在进行软件编程时不会直接使用中断,但理解它对我们来说依然重要. 我们在使用线程切换及状态管理.异常处理.硬件与处理器的交互.I/O操作等指令时,中断都在默默的为我们 ...
- CPU 多核指令 —— WFE 原理【原创】
转自:http://tinylab.org/arm-wfe/ Zhang Binghua 创作于 2020/05/19 打赏 微信公众号 知识星球 关注 @泰晓科技 与数千位一线 Linux 工程 ...
- CPU性能分析工具原理
转载请保留以下声明 作者:赵宗晟 出处:https://www.cnblogs.com/zhao-zongsheng/p/13067733.html 很多软件都要做性能分析和性能优化.很多语言都会有他 ...
- CPU 和内存虚拟化原理 - 每天5分钟玩转 OpenStack(6)
前面我们成功地把 KVM 跑起来了,有了些感性认识,这个对于初学者非常重要.不过还不够,我们多少得了解一些 KVM 的实现机制,这对以后的工作会有帮助. CPU 虚拟化 KVM 的虚拟化是需要 CPU ...
- cpu卡,sam卡原理
第一部分 CPU基础知识一.为什么用CPU卡IC卡从接口方式上分,可以分为接触式IC卡.非接触式IC卡及复合卡.从器件技术上分,可分为非加密存储卡.加密存储卡及CPU卡.非加密卡没有安全性,可以任意改 ...
随机推荐
- Docker(11)- docker ps 命令详解
如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 作用 列出容器 语法格式 doc ...
- 7_Reverse Integer
7.Reverse Integer Given a 32-bit signed integer, reverse digits of an integer. Example 1: Input: 123 ...
- 【SpringCloud】05.Eureka的高可用
1.简单情况 2.为了达到Eureka的高可用,可以多个Eureka互相注册. 3.我们需要修改两处: Eureka Client Eureka Server 3.1 Eureka Client 在C ...
- Pycharm激活码亲测有效,2020Pycharm最新激活码免费分享~
Pycharm激活码,亲测有效!!! 如果下边的Pycharm激活码过期失效了的话,大家可以关注微信公众号:Python联盟,然后回复"激活码"即可获取最新Pycharm永久激活码 ...
- 线程安全的SimpleDateFormat
import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; imp ...
- XML fragments parsed from previous mappers already contains value for
1. ssm项目报错: WARN [main] DefaultListableBeanFactory:1479-- Bean creation exception on FactoryBean t ...
- [tmp]__URL
常用排序算法稳定性.时间复杂度分析(转,有改动) http://www.cnblogs.com/nannanITeye/archive/2013/04/11/3013737.html http://w ...
- mysql yyyy-MM-dd function UNIX_TIMESTAMP('yyyy-MM-dd HH:mm:ss')
mysql yyyy-MM-dd function UNIX_TIMESTAMP('yyyy-MM-dd HH:mm:ss') select UNIX_TIMESTAMP('1997-10-04 22 ...
- ngx instance
首先看下 连接池的获取以及释放 ngx_connection_t * ngx_get_connection(ngx_socket_t s, ngx_log_t *log) //从连接池中获取一个ngx ...
- ceph的ISCSI GATEWAY
前言 最开始接触这个是在L版本的监控平台里面看到的,有个iscsi网关,但是没看到有类似的介绍,然后通过接口查询到了一些资料,当时由于有比较多的东西需要新内核,新版本的支持,所以并没有配置出来,由于内 ...