一、中斷的魅力
1、中斷在生活的魅力
比如你訂了一份外賣,但是不確定外賣什么時候送到,也沒有別的方法了解外賣的進度,但是,配送員送外賣是不等人的,
到了你這兒沒人取的話,就直接走人了。所以你指能苦苦等着,時不時去門口看看外賣送到沒,而不能干其他事情。
不過呢,如果你在訂外賣的時候,你就跟配送員約定好,讓他送到后給你打個電話,你就不用苦苦等待了,就可以去忙別的事情,
直到電話一響,接電話、取外賣就可以了
這里的"打電話",其實就是一個中斷。沒接到電話的時候,你可以做其他的事情;只有接到了電話(也就是發生中斷),你才要進行另一個動作:取外賣
這個例子你就可以發現,中斷其實就是一種異步的事件處理機制,可以提高系統的並發處理能力
2、什么是中斷?
中斷其實就是一種異步的事件處理機制,可以提高系統的並發處理能力
3、為什么要有中斷呢?
可以提高系統的並發處理能力
二、中斷的丟失
1、中斷為什么會丟失
1、由於中斷處理程序會打斷其他進程的運行,所以,為了減少對正常進程運行調度的影響,中斷處理程序需要盡可能快的運行
2、如果中斷本身做的事情不多,那么處理起來也不會又太大問題
3、但如果中斷要處理的事情很多,中斷服務程序就可能要運行很長時間
特別是,中斷處理程序在響應中斷時,還會臨時關閉中斷,這就會導致上一次中斷處理完成之前,其他中斷不能響應,也即是說中斷有可能會丟失
2、通過以取外賣理解中斷丟失
1、假如你定了2分外賣,一份主食和一份飲料,並且是由2個不同的配送員來配送。
2、兩份外賣都約定了電話取外賣的方式,但是問題又來了
3、當第一份外賣送到的,配送員給你打了個長長的電話,商量發票的處理方式,
4、與此同時,第二個配送員也到了,也想給你打電話,但是很明顯,因為電話占線(也就是關閉了中斷響應)
5、第二個配送員的電話是打不通的。所以,第二個配送員很可能試了幾次后就走掉了(也就是丟失了一次中斷)
三、如何解決中斷的丟失問題
1、Linux 將中斷處理過程分成幾個階段分別是什么?
1、Linux 將中斷處理過程分成兩個階段
2、分別是上半部用來快速處理中斷和下半部分用來延遲處理上半部分未完成的工作
3、上半部用來快速處理中斷:它在中斷禁止模式下運行,只要處理跟硬件緊密相關的時間敏感的工作
4、下半部分用來延遲處理上半部分未完成的工作:通常一內核線程的方式運行
2、通過取外賣理解上半部和下半部
上半部就是你接電話,告訴配送員你已經知道了,其他事兒見面再說,然后電話就可以掛斷了;
下半部才是取外賣的動作,以及見面后商量發票處理的動作
這樣第一個配送員不會占用你太多時間,當第二個配送員過來時,照樣能正常打通你的電話,
3、通過網卡接收數據包理解上半部和下半部
網卡接收到數據包后,會通過硬件中斷的方式,通知內核有新的數據到了,這時,內核就應該調用中斷處理程序來
響應它,你可以自己先想一下,這種情況下的上半部分和下半部分分別負責什么工作呢?
對上半部來說:
既然是快速處理,其實就是要把網卡的數據讀到內存中,然后更新一下硬件寄存器的狀態(標識數據已經讀好了),最后再發送一個軟中斷信號,通知下半部做進一步的處理
而下半部
被軟中斷信號喚醒后,需要從內存中找到網絡數據,再按照網絡協議棧,對數據進行逐層解析和處理,直到把它送給應用程序。
所以,這兩個階段你可以這樣理解:
上半部分直接處理硬件請求,也就是我們常說的硬中斷,特點是快速執行
而下半部則是由內核觸發,也就是我們常說的軟中斷,特點是延遲執行
實際上,上半部會打斷CPU正在執行的任務,然后立即執行中斷處理程序,而下半部以內核線程的方式執行,並且每個CPU都對應一個軟中斷
內核線程,名字為"ksoftirqd/CPU 編號" 比如0號CPU對應的軟中斷內核線程的名字就是ksoftirqd/0
注意事項:
軟中斷不只包括了剛剛所講的硬件設備中斷處理程序的下半部。一些內核自定義的時間也屬於軟中斷,比如內核調度和RCU鎖
(Read-Copy Update 的縮寫,RCU 是 Linux 內核中最常用的鎖之一)等。
四、查看軟中斷和內核線程
1、查看軟中斷
Ubuntu 18.04
[root@localhost ~]# cat /proc/softirqs CPU0 CPU1 CPU2 CPU3 HI: 3 1 0 0 TIMER: 25265822 43447443 10082461 12874428 NET_TX: 387749 5 1927 1 NET_RX: 28946864 41272 32597 23383 BLOCK: 888 539 1296 1162217 BLOCK_IOPOLL: 0 0 0 0 TASKLET: 39231 9 110 1 SCHED: 21957135 40794916 7650486 10479809 HRTIMER: 0 0 0 0 RCU: 2925240 2746051 2401640 2383562
centos
[root@luoahong ~]# cat /proc/softirqs CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 CPU8 CPU9 CPU10 CPU11 CPU12 CPU13 CPU14 CPU15 CPU16 CPU17 CPU18 CPU19 CPU20 CPU21 CPU22 CPU23 CPU24 CPU25 CPU26 CPU27 CPU28 CPU29 CPU30 CPU31 CPU32 CPU33 CPU34 CPU35 CPU36 CPU37 CPU38 CPU39 CPU40CPU41 CPU42 CPU43 CPU44 CPU45 CPU46 CPU47 CPU48 CPU49 CPU50 CPU51 CPU52 CPU53 CPU54 CPU55 CPU56 CPU57 CPU58 CPU59 CPU60 CPU61 CPU62 CPU63 CPU64 CPU65 CPU66 CPU67 CPU68 CPU69 CPU70 CPU71 CPU72 CPU73 CPU74 CPU75 CPU76 CPU77 CPU78 CPU79 CPU80 CPU81 CPU82 CPU83 CPU84 CPU85 CPU86 CPU87 CPU88 CPU89 CPU90 CPU91 CPU92 CPU93 CPU94 CPU95 CPU96 CPU97 CPU98 CPU99 CPU100 CPU101 CPU102 CPU103 CPU104 CPU105 CPU106 CPU107 CPU108 CPU109 CPU110 CPU111 CPU112 CPU113 CPU114 CPU115 CPU116 CPU117 CPU118 CPU119 CPU120 CPU121 CPU122 CPU123 CPU124 CPU125 CPU126 CPU127 HI: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 TIMER: 4699549 4940977 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NET_TX: 4267 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NET_RX: 605 102597 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 BLOCK: 4595883 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 BLOCK_IOPOLL: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 TASKLET: 56 1014 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SCHED: 418267 475421 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 HRTIMER: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 RCU: 389674 288935 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2、軟中斷文件注意事項
1、不過你可能發現,TASKLET在不同CPU上的分布並不均勻,TASKLET是最常用的軟中斷實現機制,每TASKLET個只運行一次就會結束,並且只在調用它的函數所在的CPU上運行。
因為使用TASKLET特別簡便,當然也會存在一些問題,比如說由於只在一個cpu上運行導致調度不均衡,再比如因為不能在多個CPU上並行運行帶來了性能限制
2、另外,剛剛提到過,軟中斷實際上是以內核線程的方式運行的,每個CPU都對應一個軟中斷內核線程,這個軟中斷內核線程叫做ksoftirqd/CPU 編號。那要怎么查看這些線程的運行呢?
[root@luoahong ~]# ps aux | grep softirq root 3 0.2 0.0 0 0 ? S 11:09 0:43 [ksoftirqd/0] root 14 0.0 0.0 0 0 ? S 11:09 0:08 [ksoftirqd/1] root 19903 0.0 0.0 112712 976 pts/0 R+ 17:04 0:00 grep --color=auto softirq
注意:這些線程的名字外面都有中括號,這說明ps無法獲取他們的命令行參數(cmline)。一般來說,ps 的輸出中,名字括在中括號里的,一般都是內核線程