【精通内核】CPU控制并发原理(二)
前言
📫作者简介: 小明java问道之路,专注于研究计算机底层/Java/Liunx 内核,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计📫
🏆 CSDN专家博主/Java优质创作者/CSDN内容合伙人、InfoQ签约作者、阿里云签约专家博主、华为云专家、51CTO专家/TOP红人 🏆
🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~
本文导读
本文讲解CPU角度的中断控制,CPU层面并行并发和中断控制的原理,现代CPU的缓存结构和架构图、CPU缓存一致性的源码原理,以及CPU如何通过编译器的屏障与指令实现系统屏障,经过内联汇编代码验证之后,证明上述所说的 Linux 内核用 volatile 关键字实现系统屏障(指令重排),加深对系统屏障的内核源码和原理的理解。
一、中断控制
本节从CPU来看看并发和并行下,硬件层是如何处理共享资源的。
如果只有一个CPU,我们肯定采用并发任务,因为没有多个CPU,所以无法并行,也就是分时复用CPU资源,即给每个任务分CPU时间片,当时间片到后切换下一个任务执行。想象一下,如我想在这种场景下实现 P-V 原语,那么应怎么做呢?
众所周知,对于变量加 1 的操作分为3步,加载、修改、写回,如果在加载完成的时候,CPU 切换了任务,那么会发生什么?肯定就回到了之前说的共享资源导致并发的问题,肯定又要上锁,那么上锁就必须要有原子性操作。
怎么解决上述问题呢?让我们先思考,是什么导致CPU下来看看任到没到达时间片呢?因为任务代码里是没有检测时间片的指令的,答案是中断那么什么是中断呢?想象一下,你在写代码,当你老板找你时给你打了个电话,于是你停下手里的工作,接你老板的电话,完毕后继续写代码,那么你放下手头完成后继续写代码的过程就叫作中断恢复。
你写代码时是电话把你中断了,那么CPU执行指令时是谁中断了CPU?答案是 CPU 一个针脚会检测中断,而这个中断信号在 intel上是由一个芯片叫作 8259A中断控制芯片 来做的。
图中有两块 8259A 芯片,每块芯片可以管理8个中断源,通过使用多片级联的方式,那么最多可以管理64个不同的中断号(排列组合,芯片上只有8个中断源针脚,那么8个有8个中断源的8259A芯片是多少 8*8=64),图中采用了两块芯片,可以管理15级中断号(IR2连接了第2块的INT针脚,那么还剩7个,片2有RO-R7总共7个,7+8=15)。
这里将级联的芯片称为从芯片,而将直接跟 CPU 的 INTR 针脚(也就是 CPU Interrupt Request CPU中断请求针脚)相连的芯片称为主芯片。
从芯片的 INT 引脚连接到主芯片的 IR2 引脚上。主芯片的端口基地址为 0x20,从芯片的地址为 0xA0。我们可以在操作系统初始化时通过系统总线控制器,CPU用 IN或者OUT 命令对 8259A 操作。
完成编程后,首先芯片就开始工作,随时响应连接到IR0-IR15针脚的信号,再通过CPUINTR针脚通知给CPU。然后CPU 响应这个信号,通过数据总线 D0-D7 将我们通过编程设定的中断号读出,接着 CPU就可以知道是哪个中断了我,最后根据这个中断号去调用响应的中断服务程序。
其实CPU就是通过检测 INTR 针脚信号来判断是否有中断,问题来了什么时候检测呢?在执行完一条指令,当开始执行下一个指令之前检测中断信号。
回顾CPU如何执行指令? IF(instruction fetch指令提取)、ID(instruction decode指令译码)、EX(execute执行阶段)、MEM(memory访存阶段)、WB(writeback写回阶段)、IE(interrupt execute中断处理阶段)。
下面来看看Linux内核是如何操作的。Linux 内核中对于中断的宏定义:
#define local irq_disable()_asm__volatile_("cli":::"memory") // 关中断
#define local_irq_enable()__asm__volatile_("sti":::"memory") // 开中断
回到我们之前的问题上,如果在 CPU 上执行 P-V 原语呢?也就是如何让 CPU 不会切换任务,很简单,通过一种方式让 CPU 不响应INTR针脚的中断信号就行了,当我们执行完原子性的操作后,再让 CPU 响应INTR 信号即可,那么这两个过程就叫作:中断使能、关中断。对应着两个 CPU 指令,即 STI(set interrupt flag设置中断标志位)和 CLI(clear interrupt flag清除中断标志位)。
总结
本文讲解CPU角度的中断控制,CPU层面并行并发和中断控制的原理,现代CPU的缓存结构和架构图、CPU缓存一致性的源码原理,以及CPU如何通过编译器的屏障与指令实现系统屏障,经过内联汇编代码验证之后,证明上述所说的 Linux 内核用 volatile 关键字实现系统屏障(指令重排),加深对系统屏障的内核源码和原理的理解。
转载自:https://juejin.cn/post/7145857645923172365