中断是一种异步的事件处理机制,可以有效的提高系统的并发处理能力。
可以举一个例子,比如你在外卖平台定了一份外卖,但是这个平台并没有预估送达时间,而且配送员送到了也不会敲门按门铃,到了如果没人拿他就直接跑了。所以你只能苦苦的坐在门口等待外卖员上门,直到拿到你的外卖。这种形式就叫做不可中断状态,因为你在等外卖的时候不能做其他事情。
但是如果你的外卖平台具有实时进度提醒,且外卖员送达后会电话联系你出来拿外卖。那么你就可以下单后去做其他的事,直到电话响了你再接电话、取外卖就行了。在这里,打电话就是一个中断,在没收到电话的时候你持续做另一件事,直到接到电话(发生中断)才执行其他动作——取外卖。
由于中断处理程序会打断其他程序的运行,所以为了减少对正常进程运行调度的影响,中断处理程序就需要尽可能快地运行。如果中断本身要做的事情不多,那么处理起来也不会有太大的问题;但如果中断本身要处理的事情太多,中断服务程序就有可能要运行很长时间。
特别是中断处理程序在响应中断时,还会临时关闭中断。这就会导致上一次中断处理完成之前,其他中断程序都不能响应,也就是说中断可能会丢失。
还是以外卖为例,这次你下单了两份外卖,一份炸鸡跟一份奶茶,并且是由两个外卖小哥配送,同时他们到了之后又都会给你打电话通知外卖送达。但这次,你的奶茶送到时,由于配送出了问题导致奶茶破损,于是你在电话里头跟外卖小哥沟通售后/赔偿事宜沟通了很久。于此同时你的炸鸡也到了,但是你的电话在跟奶茶的外卖小哥沟通导致了电话占线(系统关闭了中断响应),导致炸鸡的外卖小哥无法联系上你,于是他可能试了几次就走掉了(中断丢失)。
如果你弄清了上面的“取外卖”模式,那对系统的中断机制就很容易理解了。事实上,为了解决中断处理程序执行过长导致中断丢失的问题,Linux 将中断处理过程分成了两个阶段,也就是上半部和下半部:
上半部用来处理快速中断,它在中断禁止模式下运行,主要处理跟硬件紧密相关的或时间敏感的工作。
下半部用来延迟处理上半部未完成的工作,通常以内核线程的方式运行。
还是“炸鸡与奶茶”的例子,上半部就是你接电话,告诉外卖小哥你已经知道了,晚点你上外卖平台申请理赔就行了,然后电话就挂了;下半部才是在外卖平台申请理赔等动作。这样,第一个外卖小哥不会占用你太多时间,当第二个外卖小哥到了的时候,照样能打通你的电话。
所以,这两个阶段也能这么理解:
上半部直接处理硬件请求,也就是我们常说的硬中断,特点是快速执行
下半部则是由内核触发,也就是我们常说的软中断,特点是延迟执行
可以通过 proc 文件系统来查看捏合数据结构,其中
/proc/softirqs 提供软中断的运行情况
/proc/interrupts 提供硬中断的运行情况
/proc/softirqs 文件示例
$ cat /proc/softirqs
CPU0 CPU1
HI: 1 0
TIMER: 78492795 69611989
NET_TX: 0 1
NET_RX: 3359701 3080468
BLOCK: 3842791 0
BLOCK_IOPOLL: 0 0
TASKLET: 16 0
SCHED: 27857273 29745084
HRTIMER: 0 0
RCU: 42876951 37899812注意点
软中断类型:也就是这个界面的第一列的内容,从第一列可以看到软中断分为 10 种类型
同一种中断在不同 CPU 上的分布情况:正常情况下,同一种中断在不同 CPU 上的累计次数应该差不多
TASKLET 在不同 CPU 上的分布不均匀:TASKLET 是最常用的软中断实现机制,每个 TASKLET 只运行一次就会结束,且只在调用它函数所在的 CPU 上运行,因此 TASKLET 非常简便。不过也会存在一些问题,比如只在一个 CPU 上运行导致调度不均匀,或不能在多个 CPU 上并行运行带来的性能限制
查看软中断线程,可以通过查找编号为 ksoftirqd/CPU 的进程,比如下面指令:
$ ps -aux | grep softirq
root 6 0.0 0.0 0 0 ? S Apr06 0:01 [ksoftirqd/0]
root 14 0.0 0.0 0 0 ? S Apr06 0:01 [ksoftirqd/1]
root 12720 0.0 0.0 112816 980 pts/6 S+ 22:59 0:00 grep --color=auto softirq注意,这些线程的名字外面都有中括号的,这说明 ps 无法获取他们的命令行参数(cmdline)。一般来说,ps 的输出汇总,名字在中括号里的,一般都是内核线程。
一般情况下,软中断升高在 top 中不容易发现,但给人的感觉是 shell 反应很迟缓,敲下回车都会卡一会。观察软中断升高速率可以使用 watch 来观察,之后再对症下药即可。
watch -d cat /proc/softirqs
CPU0 CPU1
HI: 1 0
TIMER: 78516628 69634209
NET_TX: 0 1
NET_RX: 3360907 3081073
BLOCK: 3843820 0
BLOCK_IOPOLL: 0 0
TASKLET: 16 0
SCHED: 27866184 29754814
HRTIMER: 0 0
RCU: 42890013 37911964Linux 中的中断处理程序分为上半部和下半部:
上半部对应硬件中断,用来快速处理中断
下半部对应软中断,用来异步处理上半部未完成的工作
Linux 中的软中断包括网络收发、定时、调度、RCU 锁等各种类型,可以通过查看 /proc/softirqs 来观察软中断的运行情况。