🎁個人主頁:工藤新一1
🔍系列專欄:C++面向對象(類和對象篇)
🌟心中的天空之城,終會照亮我前方的路
🎉歡迎大家點贊👍評論📝收藏?文章
文章目錄
- 進程優先級(Process Priority)
- 一、回顧:進程狀態
- 二、進程優先級
- 2.1基本概念
- 2.2查看系統進程
- 2.3 PRI vs NI
- 2.4 查看進程優先級的命令
- 三、 優先級存在的意義
- 3.1 應對任務的重要性差異(關鍵型任務優先)
- 3.2 滿足任務的時效性要求(實時性任務優先)
- 3.3 提升整體系統效率和用戶體驗(CPU空閑時間利用)
- 3.4 實現資源的合理分配與公平性(防止餓死)
- 3.5 匹配任務的資源需求特征(I/O消耗型 vs. CPU消耗型)
- 一個生動的比喻
進程優先級(Process Priority)
一、回顧:進程狀態
-
1. 狀態是變量:進程狀態在代碼上是一個可修改的整型變量(
task_struct->state
),不同的值代表不同的狀態宏 -
2. 狀態決定隊列:這個狀態值直接決定了進程應該位于哪個隊列(運行隊列 or 各種等待隊列)。進程在哪里,就決定了它的行為
-
3. 隊列決定命運:
- 在運行隊列 -> 有資格被CPU調度 -> 表現為“運行”或“就緒”
- 在等待隊列 -> 不會被CPU調度 -> 表現為“阻塞”、“睡眠”、“卡住”
- 被交換到磁盤 -> 既是阻塞,又不在內存 -> 表現為“掛起
a. 本質:task_struct
中的狀態標志(state
字段)
- 這是狀態的“源代碼視角”或“靜態視角”。在 Linux 內核中,每個進程/線程都是一個
task_struct
結構體(稱為進程描述符)。其中有一個關鍵的成員變量,比如volatile long state;
,它是一個整數。 - 這個整數的值不是任意的,它由內核預先定義好的一系列宏來決定,例如:
TASK_RUNNING
: 可運行狀態。TASK_INTERRUPTIBLE
: 可中斷的睡眠狀態(一種阻塞)。TASK_UNINTERRUPTIBLE
: 不可中斷的睡眠狀態(另一種阻塞,通常發生在等待硬件I/O時)。__TASK_STOPPED
: 暫停狀態(如收到SIGSTOP
信號)。TASK_DEAD
/EXIT_ZOMBIE
: 退出狀態。
- 您的結論完全正確:修改這個
state
變量的值,就改變了內核對這個進程狀態的“官方認定”。
b. 行為:隊列決定調度(運行 vs. 阻塞)
- 這是狀態的“內核調度視角”或“動態視角”。內核的調度器(Scheduler)不關心
state
這個數字本身,它只關心隊列。調度器的核心工作就是從運行隊列(Runqueue) 里選擇一個最合適的進程來運行。 - 運行(RUNNING):當一個進程的
state
為TASK_RUNNING
時,它有資格被調度。此時,它一定存在于某個CPU的運行隊列中(或者正在某個CPU上執行)。調度器只從這個隊列里選人。 - 阻塞/睡眠(BLOCKED/SLEEPING):當一個進程需要等待某個事件(如
scanf
等待鍵盤輸入、read
等待磁盤數據、sleep
等待超時)時,內核會:- 將其
state
設置為TASK_INTERRUPTIBLE
或TASK_UNINTERRUPTIBLE
。 - 將其從運行隊列中移除。
- 將其加入到另一個等待隊列(Wait Queue) 中,這個等待隊列通常與它正在等待的資源(如鍵盤、硬盤的某個塊)相關聯。
- 將其
- 此時,因為這個進程已經不在運行隊列里了,調度器根本看不到它,所以它絕對沒有機會獲得CPU,這就是它“卡住了”的原因。
c. 狀態轉換的完整流程
讓我們用 scanf
的例子來串聯這兩個視角:
- 進程運行:進程在CPU上執行,
state = TASK_RUNNING
,位于運行隊列。 - 調用
scanf
:進程執行到scanf
系統調用,代碼進入內核態。 - 內核檢查資源:內核發現鍵盤緩沖區中沒有數據(用戶還沒輸入)。
- 狀態改變與隊列操作:
- 內核將進程的
state
從TASK_RUNNING
修改為TASK_INTERRUPTIBLE
。 - 內核將進程的
task_struct
從運行隊列中摘下。 - 內核將進程的
task_struct
加入到“鍵盤輸入等待隊列”中。
- 內核將進程的
- 調度切換:內核調用調度器,切換到另一個就緒的進程運行。
- 事件發生:用戶按下鍵盤,觸發硬件中斷。鍵盤中斷處理程序工作,將按鍵數據放入緩沖區。
- 喚醒進程:中斷處理程序調用
wake_up
函數,它會找到“鍵盤輸入等待隊列”中的進程,并:- 將其
state
修改回TASK_RUNNING
。 - 將其 從等待隊列中摘下。
- 將其 重新放回運行隊列。
- 將其
- 再次被調度:在未來的某個時刻,調度器再次選中這個進程,它就從
scanf
系統調用中返回,繼續執行,并讀取到輸入數據。
d. 關于“掛起(Suspended)”
您還提到了“掛起”,這是一個很好的延伸。掛起通常不是Linux內核原生的一個狀態宏,而是一種行為,通常發生在內存壓力很大時。
- 行為:內核需要騰出物理內存(RAM)。它會選擇一個處于阻塞狀態(
TASK_INTERRUPTIBLE
或TASK_UNINTERRUPTIBLE
)的進程,將其占用的內存數據交換(Swap Out)到磁盤上。此時,這個進程除了在等待隊列里,它的代碼和數據都不在內存中了。 - 狀態:它的
state
可能仍然是TASK_INTERRUPTIBLE
,但它多了一個“被換出”的屬性。當它等待的事件到來(被喚醒)時,內核首先需要把它的內存數據從磁盤換回(Swap In)到內存,然后才能將其加入運行隊列,這個過程會有明顯的延遲。
二、進程優先級
2.1基本概念
進程優先級 是一個決定進程如何被 CPU
調度器對待的關鍵屬性,理解優先級的核心是:在多個可運行(RUNNABLE)的進程競爭 CPU 時,優先級高的進程有更大的機會被調度器選中執行
抽象化的理解:我們車站排隊,排隊的本質是確認優先級,確認了優先級,我們就能知道什么時候可以上車。
優先級的本質是:衡量得到某種資源的先后順序。同樣地,對進程來講:優先級是進程得到 CPU資源的先后順序
- 優先級:能得到資源(先后問題)
- 權限:是否得到某種資源
2.2查看系統進程
我們很容易注意到其中的?個重要信息,有下:
? UID:執?者的?份(user id)
? PID:進程的代號
? PPID:進程是由哪個進程發展衍??來的,亦即?進程的代號
? PRI:進程可被執?的優先級(程序被CPU執行的先后順序),其值越?越早被執?(默認80,且始終為默認值)
? NI:進程的nice值,進程優先級的修正數據(默認0)
進程的真實優先級PRI(new) == PRI(old默認) + NI
2.3 PRI vs NI
- 需要強調?點的是,進程的nice值不是進程的優先級,他們不是?個概念,但是進程nice值會影 響到進程的優先級變化
- 可以理解nice值是進程優先級的修正修正數據
- 所以,調整進程優先級,在Linux下,就是調整進程nice值,nice其取值范圍:[-20, 19],?共40個級別。Linux進程優先級(PRI):[60, 99]
2.4 查看進程優先級的命令
? top 指令更改已存在進程的nice:
? top
? 進?top后按“r”?>輸?進程PID?>輸?nice值
注意:
? 其他調整優先級的命令:nice,renice
? 系統函數:
三、 優先級存在的意義
“進程優先級”的存在絕非偶然,它是解決計算機系統中資源競爭與任務多樣性之間矛盾的根本性方案
“我們”為何在火車站要排隊?進程又為何在 CPU
上排隊呢?
目標資源稀缺,導致要通過優先級確認誰先誰后的問題!
3.1 應對任務的重要性差異(關鍵型任務優先)
不是所有任務都生而平等。系統必須能夠區分哪些任務關乎全局,哪些任務只是錦上添花。
- 例子:
- 高優先級:鍵盤輸入處理。當你按下
Ctrl+C
試圖終止一個失控的程序時,系統必須立即響應這個中斷,否則用戶會失去對機器的控制。如果鍵盤處理程序和后臺的文件壓縮任務平等競爭CPU,用戶可能會感覺系統“卡死”了。 - 低優先級:后臺文件備份、軟件更新、病毒掃描。這些任務很重要,但不需要立即完成。它們可以悄無聲息地在系統空閑時利用資源,而不影響你的正常工作。
- 高優先級:鍵盤輸入處理。當你按下
- 目的:確保關鍵任務總能得到及時響應,維持系統的可用性和響應性。
3.2 滿足任務的時效性要求(實時性任務優先)
某些任務有嚴格的時間期限(Deadline),錯過期限會導致結果錯誤或完全失效。
- 例子:
- 視頻播放:解碼器必須在下一幀需要顯示之前完成解碼工作,否則視頻就會卡頓。
- 工業控制:機器人傳感器數據處理必須在幾毫秒內完成,并發出控制指令,否則可能導致生產事故。
- 音頻處理:聲音緩沖區必須被及時填充,否則會產生刺耳的爆破音。
- 目的:通過賦予實時進程最高的優先級,保證時間敏感型任務能夠搶占CPU,按時完成。這就是實時優先級(1-99)存在的意義。
3.3 提升整體系統效率和用戶體驗(CPU空閑時間利用)
系統資源(尤其是CPU)經常會出現短暫的閑置狀態。優先級機制允許系統**“見縫插針**”地利用這些碎片時間。
- 例子:你在編輯文檔時,每次思考或停頓的瞬間,CPU利用率都會驟降。一個低優先級的進程(如索引服務的文件索引器)就可以在這個時候被調度運行,進行一些計算。
- 目的:最大化資源利用率。讓低優先級任務填充高優先級任務之間的空閑時間,從而提升系統的整體吞吐量,同時還不會讓用戶感覺到任何卡頓。
3.4 實現資源的合理分配與公平性(防止餓死)
如果沒有優先級,所有進程完全平等地分享CPU時間(即“輪轉”調度),對于一些需要大量計算的后臺任務來說是公平的,但對于需要交互的用戶來說卻是災難性的。你的每次點擊可能都要等一個時間片輪完才能被響應。
優先級機制引入了一種受控的不公平:
- 交互式進程(如桌面、瀏覽器、IDE)被賦予較高優先級,從而獲得更快的響應速度,提升用戶體驗。
- 批處理進程(如編譯大型項目、科學計算)被賦予較低優先級,它們可以充分利用系統空閑資源,但不會拖慢前臺工作。
同時,調度器(如CFS)會保證即使是最低優先級的進程(Nice +19)也能最終獲得一定的CPU時間,防止其被完全“餓死(Starvation)”。
即,優先級設立不合理[大量等級差過大進程],會導致優先級低的進程長時間得不到 CPU資源,進而導致:進程饑餓
3.5 匹配任務的資源需求特征(I/O消耗型 vs. CPU消耗型)
進程通常分為兩類:
- I/O消耗型進程:大部分時間在等待I/O操作(如磁盤讀寫、網絡請求)。例如,Web服務器、文本編輯器。它們需要的是在I/O完成時能被快速響應,以便發起下一個請求。因此,它們應該被賦予較高優先級。
- CPU消耗型進程:大部分時間在進行數學計算。例如,視頻編碼、數據建模。它們一旦獲得CPU就會長時間占用。它們應該被賦予較低優先級,以免影響系統的交互性。
優先級機制幫助調度器更好地識別和區分這兩種類型的進程,并采取不同的調度策略。
一個生動的比喻
你可以把CPU想象成一個醫院的急診室。
- 實時優先級進程:是生命垂危、需要立即搶救的病人(如心臟驟停)。他們擁有最高優先級,一來就必須立刻處理,所有醫生都要圍上來。
- 高優先級進程(Nice值低):是突發急癥的病人(如高燒、嚴重外傷)。他們需要很快被醫生接診。
- 普通優先級進程(Nice=0):是普通急診病人(如感冒、腸胃炎)。按掛號順序排隊等候。
- 低優先級進程(Nice值高):是來做體檢或打疫苗的人。他們不緊急,可以在所有急診病人都處理完后,或者夜深人靜醫院空閑時再來。
如果沒有這個優先級分診系統,讓所有病人(進程)完全平等地排隊,那么生命垂危的病人可能還沒排到就去世了(系統無響應)。而有了優先級,醫院(操作系統)就能最大限度地拯救生命(保證關鍵任務),同時又能高效地處理所有病人(提升整體吞吐量),并確保每個人最終都能得到治療(防止餓死)。
因此,進程優先級是現代操作系統中一項至關重要的機制,它優雅地平衡了效率、響應性、公平性和資源利用率這多個相互沖突的目標。
🌟 各位看官好,我是工藤新一1呀~
🌈 愿各位心中所想,終有所致!