【精通内核】CPU控制并发原理(三)

201 阅读5分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第5篇文章,点击查看活动详情image.png  

前言

📫作者简介: 小明java问道之路,专注于研究计算机底层/Java/Liunx 内核,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计📫 

🏆 CSDN专家博主/Java优质创作者/CSDN内容合伙人、InfoQ签约作者、阿里云签约专家博主、华为云专家、51CTO专家/TOP红人 🏆

🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~

本文导读

本文讲解CPU角度的中断控制,CPU层面并行并发和中断控制的原理,现代CPU的缓存结构和架构图、CPU缓存一致性的源码原理,以及CPU如何通过编译器的屏障与指令实现系统屏障,经过内联汇编代码验证之后,证明上述所说的 Linux 内核用 volatile 关键字实现系统屏障(指令重排),加深对系统屏障的内核源码和原理的理解。

一、CPU的结构与缓存一致性

1、现代CPU架构

现代CPU架构除了在片上继承多个核以外,还有为了减少对内存访问增加了多级缓存来提高运行速度。通常是三级缓存,及L1(核内独享)L2(核内独享)L3(核外共享)

上图描述了现代 CPU 的架构,每个 CPU 独立有 L1和L2 缓存,而共享 L3 缓存。假如我们有两个任务A和B,它们对 counter变量的加1是这样的,任务 A和B 其中一个访存,通过总线总裁只有一个任务能够通过数据总线和地址总线,把counter变量从内存中加载放入 L3缓存 中,然后任务 A和B 分别把 counter 加载到自己的 L1、L2 缓存中,接着进行操作,操作完毕后,只需要把结果放入缓存中即可。来考虑会出现什么问题?如果任务A获得了锁,并且在修改了 counter后放到了自己的L1缓存中,同样任务B也如此,那么问题来了,当任务A释放了锁,这时任务B获得了锁,情况又当如何呢?

由于counter的最新值在任务A的L1缓存中,这可怎么办?任务B所在的 CPU 的缓存上是旧值,应如何保证程序的正确性?这就是缓存一致性协议。

2、缓存一致性

来看看intel的MESI缓存一致性协议的状态描述

上述状态的描述非常容易理解,L1、L2、L3 的缓存是一行一行排列的,我们称之为缓存行,那么4 种状态,即modified、exclusive、shared、invalid 就是在缓存行中保留了两个状态位分别可以表示4种状态。

那么分别代表什么意思呢?从上述描述中应该就能够大致猜出这是什么状态了。例如 CPU 1加载了 counter 值,那么 counter 在缓存行中的状态为E状态,当CPU2加载 counter 值时,CPU1窥探到总线上再到内存中加载 counter 值,那么就会把自己缓存行中的数据放入 CPU2 的缓存行中,且把自己状态修改为S状态,表明 CPU1 和 CPU2 共享 counter 变量。而当CPU1获得了锁并且修收了 counter 值时,CPU 1中的 counter 缓存行状态就变为 M 状态,并且 CPU 2 窥探到 counter 值已经改变,可将缓存行状态变为1状态,此时当CPU 2在操作 counter 值时,由于CPU2的缓存行无效,因此就会重新从CPU 1中将counter的最新值加载至其中。这就保证了不同 CPU 中缓存一致性。

二、总结下CPU缓存一致性

(1) 一个处于 M 状态的缓存行,必须时刻监听所有试图读取该缓存行对应的主存地址的操作,如果监听到,则必须在此操作执行前把其缓存行中的数据写回内存中,或者将该值转发给需要这个值的 CPU,然后将状态修改为 S。

(2) 一个处于S状态的缓存行,必须时刻监听使该缓存行无效或者独享该缓存行的请求,如果监听到,则必须把其缓存行状态设置为I。

(3) 一个处于E状态的缓存行,必须时刻监听其他试图读取该缓存行对应的主存地址的操作,如果监听到,则必须将其缓存行状态设置为S,并且转发值给需需要的 CPU缓存行。

(4) 当CPU需要读取数据时,如果其缓存行的状态是 I,则需要重新发起读取请求,并把自己状态变成 S;如果不是 I,则可以直接读取缓存中的值,但在此之前,必须要等待其他 CPU 的监听结果,如其他CPU也有该数据的缓存且状态是M,则需要等待其把缓存更新到内存或者转发后,再次读取。

(5) 当CPU需要写数据时,只有在其缓存行是 M或者 E 时才能执行,否则需要发出特殊的 RFO指令(read for ownership,这是一种总线事务),通知其他CPU置缓存无效(I),这种情况下性能开销是相对较大的。在写入完成后,修改其缓存状态为 M。

总结

本文讲解CPU角度的中断控制,CPU层面并行并发和中断控制的原理,现代CPU的缓存结构和架构图、CPU缓存一致性的源码原理,以及CPU如何通过编译器的屏障与指令实现系统屏障,经过内联汇编代码验证之后,证明上述所说的 Linux 内核用 volatile 关键字实现系统屏障(指令重排),加深对系统屏障的内核源码和原理的理解。