???~~~~~~歡迎光臨知星小度博客空間~~~~~~???
???零星地變得優秀~也能拼湊出星河~???
???我們一起努力成為更好的自己~???
???如果這一篇博客對你有幫助~別忘了點贊分享哦~???
???如果有什么問題可以評論區留言或者私信我哦~???
??????個人主頁??????
????????前面我們已經學習了進程的前置知識,今天這一篇博客我們繼續來學習進程,準備好了嗎~我們發車去探索進程的奧秘啦~🚗🚗🚗🚗🚗🚗
目錄
進程優先級😜
基本概念😘
Linux 中的進程優先級😍
PRI 和 NI😜
優先級計算公式😄
查看進程優先級😀
調整進程優先級的方法😋
使用 nice 和 renice 命令🙃
使用 top 命令動態調整😁
使用系統調用 setpriority 和 getpriority👍
總結與對比🐷
進程的競爭性、獨立性、并行與并發😊
進程切換(Context Switching)😀
什么是進程切換?😊
為什么會進程切換??
進程切換步驟😭
Linux O(1) 調度器😍
理論核心架構😜
調度過程 😜
隊列交換 🙃
為什么叫O(1)算法?👌
總結🐷
進程優先級😜
基本概念😘
1. 什么是進程優先級?
? ? 進程優先級(Priority)是操作系統調度器用來決定哪個進程先獲得 CPU 資源的一種機制,優先級高的進程會優先被調度執行。注意優先級與“權限”不同:優先級決定的是“誰先誰后”,而權限決定的是“能否訪問”。
2. 為什么需要進程優先級?
? ? 資源有限性:CPU 資源有限,而進程數量眾多,需要通過優先級合理分配資源。
? ? 系統性能優化:通過調整進程優先級,可以確保關鍵任務優先執行,提升系統整體性能。
Linux 中的進程優先級😍
PRI 和 NI😜
? ? PRI(Priority):進程的實際優先級,值越小優先級越高。
? ? NI(Nice):用于調整 PRI 的修正值,用戶可通過修改 NI 來間接影響 PRI。
優先級計算公式😄
PRInew?=PRIold?+nice
? ? ????????nice 的取值范圍為 -20 到 19,共 40 個級別【Linux 是一個分時操作系統,這一個范圍也保證了一定的公平公正】,過度調高某個進程的優先級可能導致其他進程“饑餓”【其他進程無法得到調度和CPU資源】。
? ? ????????PRI 的范圍一般為 60 到 99(Linux 默認范圍),Nice 值的 40 個級別(-20 到 19)正好一對一地映射到優先級(PRI)的 40 個級別(60 到 99)上。
NI
是用戶可見的、可調整的“輸入”,而PRI
是內核內部實際使用的“輸出”值。
查看進程優先級😀
使用 ps -l 或 ps -al 命令
? ? 我們可以發現【ps -l】和【ps -al】查詢到的進程是兩種不同的結果~這也就是它們的區別所在,我們來看看下面的對比表格~
特性 | ps -l | ps -al |
---|---|---|
顯示范圍 | 僅當前終端 | 所有終端 |
用戶范圍 | 僅當前用戶 | 所有用戶 |
進程數量 | 較少 | 較多 |
終端顯示 | 僅當前終端 (pts/0) | 多個終端 (pts/0, pts/1) |
? ? ? ? 除此之外,我們還可以發現進程的 PRI
?都為 80,NI
?都為 0——這正是 Linux 進程調度默認行為的體現~
????????在大多數 Linux 系統中,80 是用戶進程啟動時的默認基準優先級。這個值(具體數值可能因內核版本和發行版略有不同,但 80 非常常見)被設計為調度隊列中的一個中間值。這意味著新創建的進程不會天然地擁有很高或很低的優先級,它們在競爭 CPU 時間時處于一個相對公平的起跑線上。
????????0 是默認的 Nice 值。Nice 值是用戶或系統用來對默認優先級進行微調的修正值。一個為 0 的 NI 值表示“不做任何調整”,所以進程的最終優先級 PRI
就等于默認的基準優先級 80 + 0 = 80
。
調整進程優先級的方法😋
使用 nice
和 renice
命令🙃
?????????nice 用于啟動一個進程并指定其 nice 值,renice 用于修改已運行進程的 nice 值~
非特權用戶只能調低優先級(提高 nice 值),不能調高(降低 nice 值)~
# 啟動一個進程(code)并設置 nice 值為 10
nice -n 10 ./code# 修改已運行進程(PID=4340)的 nice 值為 5
renice -n 15 -p 4340
注意事項:普通用戶只能降低優先級(增加 NI 值),只有 root 用戶才能提高優先級(設置負的 NI 值)。
nice
用于啟動新進程時設置,renice
用于修改已運行進程的優先級。
使用 top
命令動態調整😁
命令行輸入top;
按
r
;輸入進程 PID;
輸入新的 nice 值。
按q退出
注意事項:這是交互式實時調整,同樣受權限限制(普通用戶不能設置負值)【與
renice
命令完全相同。在top
界面中,如果你是普通用戶,嘗試輸入負值會得到“Operation not permitted”
的錯誤】修改僅對進程的當前運行實例有效,進程重啟后恢復默認優先級。
使用系統調用 setpriority
和 getpriority👍
注意事項:需要在程序代碼中調用,主要權限限制與命令行相同。必須包含完善的錯誤處理(如檢查返回值),適合在應用程序中實現自適應的優先級管理。
總結與對比🐷
特性 | nice / renice 命令 | top 命令 | 系統調用 |
---|---|---|---|
使用場景 | 命令行、腳本 | 交互式實時監控與調整 | 程序內部集成 |
控制對象 | 新進程 / 已存在進程 | 已存在進程 | 自身或其他進程(編程控制) |
靈活性 | 高 | 交互式,中 | 最高,可編程邏輯控制 |
權限要求 | 普通用戶只能降級 | 普通用戶只能降級 | 普通用戶只能降級 |
持久性 | 進程運行期間有效 | 進程運行期間有效 | 進程運行期間有效 |
主要優勢 | 簡單直接,易于腳本化 | 實時直觀,結合系統監控 | 靈活自動化,嵌入程序邏輯 |
通用重要注意事項:
權限是核心:記住
-20
到-1
?【負值】的區間是 root 的“特權區”。公平性:不要濫用高優先級,否則可能導致系統資源饑餓(Starvation),影響其他重要進程和系統整體穩定性。
非永久性:所有修改都只在進程生命周期內有效,進程重啟后設置失效。
進程的競爭性、獨立性、并行與并發😊
競爭性:多個進程競爭有限的 CPU 資源,優先級用于解決競爭問題。
獨立性:進程之間相互隔離,一個進程的崩潰不會直接影響其他進程。
并行:多個進程在多個 CPU 核心上同時執行。
并發:多個進程在一個 CPU 核心上通過時間片輪轉交替執行,宏觀上間隔時間很短看似同時運行。
進程切換(Context Switching)😀
什么是進程切換?😊
????????進程切換是指操作系統將當前正在運行的進程掛起,并恢復另一個進程執行的過程。這個過程也叫做 CPU 上下文切換(CPU Context Switching)。
? ????????? 那么什么是上下文呢?前面對于進程學習,我們簡單介紹了一下上下文數據~? ?接下來我們來看看什么是CPU上下文?
理論:CPU上下文指的是在任務(進程/線程)執行時,CPU寄存器和程序計數器在任意時刻的狀態。CPU內的寄存器只有一份,但是上下文可以有多份,分別對應不同的進程。寄存器存儲著進程的臨時數據、地址、狀態信息,程序計數器(PC)存儲著下一條要執行的指令地址。
比喻:這就像 一個廚師的工作臺當前狀態——哪些食材正在處理、刀放在哪、火開到多大、菜譜翻到了哪一頁。這一切定義了“工作做到哪一步了”。
為什么會進程切換??
理論:操作系統為了實現并發(Concurrency),讓多個進程在一段時間內“看起來”同時運行。當一個進程的時間片用完、或需要等待I/O操作、或有更高優先級進程就緒時,就需要切換。
比喻:餐廳經理(操作系統)為了保證公平性和效率,規定每個廚師一次只能在廚房工作一段時間(時間片)。時間到了就必須換人,讓其他廚師也能用廚房,防止一個廚師霸占廚房。
進程切換步驟😭
-
保存上下文 (Save the Context):
-
理論:將當前進程的CPU寄存器狀態全部保存到它的內核棧(Kernel Stack) 中。
-
比喻:廚師A被叫出廚房前,他必須迅速而準確地在自己的記事本(內核棧) 上記下所有工作狀態:“洋蔥切了一半,還剩3個,湯用中火燉了5分鐘,鹽放了2勺...”。
-
-
選擇下一個進程 (Pick Next Process):
-
理論:由操作系統的調度器(Scheduler) 從就緒隊列中選擇一個最合適的進程來運行。
-
比喻:餐廳經理查看任務板(運行隊列),根據優先級規則,決定接下來讓哪位廚師(進程)進入廚房。
-
-
恢復上下文 (Restore the Context):
-
理論:將下一個要運行進程的上下文信息,從其內核棧中加載到CPU的各個寄存器中。
-
比喻:廚師B進入廚房。他并不關心上一位廚師做了什么。他拿出自己的記事本,按照上面的記錄恢復工作現場:“哦,我上次魚煎到一半,油溫是七成熱,下一步該翻面了...”。
-
-
跳轉執行 (Jump and Execute):
-
理論:將程序計數器(PC)設置為新進程的下一條指令地址,CPU開始執行新進程的代碼。
-
比喻:廚師B看了一眼記事本上記錄的下一步驟,然后開始繼續操作。
-
Linux O(1) 調度器😍
理論核心架構😜
運行隊列 (Runqueue):
理論:Linux為每個CPU核心都維護一個
struct runqueue
(運行隊列)結構。這是調度的核心數據結構。比喻:這家餐廳的每個廚房(CPU核心) 都有自己獨立的任務管理區(運行隊列),這樣多個廚房可以同時工作,互不干擾,避免了廚師們擠在一個任務板前爭吵(避免了鎖競爭)。
優先級數組 (Priority Arrays) - 活動隊列與過期隊列:
理論:每個運行隊列包含兩個
prio_array_t
結構的數組:活動隊列(active) 和 過期隊列(expired)。
活動隊列 (active):存放所有時間片尚未耗盡的就緒進程。
過期隊列 (expired):存放所有時間片已經耗盡的就緒進程【新增進程/時間片到了的進程】
比喻:每個廚房的任務管理區都有兩塊巨大的白板:
“正在叫號”板 (Active Board):上面掛著所有還有工作時間的廚師的訂單。
“等待換班”板 (Expired Board):上面掛著所有工作時間已用完的廚師的訂單。
隊列結構 (Queue Structure):
理論:每個
prio_array_t
包含:
queue[140]
: 一個包含140個鏈表的數組。每個鏈表(queue[i]
)都是一個FIFO隊列,存放著所有優先級為i
的進程。下標即優先級,目前我們主要了解O(1)調度算法如何管理調度下標為【100-139】的普通進程,【0-99】的實時進程的管理調度后面再繼續了解~
bitmap[5]
: 一個5*32=160位的位圖(bitmap),每一位代表一個優先級隊列是否為空(1為非空,0為空)。用于快速查找最高優先級的非空隊列。比喻:
“正在叫號”白板上有140個掛鉤(
queue[140]
),編號從0到139。編號越小,代表優先級越高(VIP掛鉤)。每個掛鉤上可以掛一串訂單(進程鏈表),同一掛鉤上的訂單優先級相同,按先來后到的順序排隊。
經理手邊還有一個電子指示屏(
bitmap
),上面有140個小燈,每個燈對應一個掛鉤。如果某個掛鉤上有訂單,對應的燈就會亮起。經理一眼掃過屏幕,就能立刻知道哪個編號最小的亮燈掛鉤(即最高優先級的非空隊列)。
更加形象可以看看下面這張圖片:
調度過程 😜
理論步驟:
調度器查看
active->bitmap
,找到第一個被設置的位(即優先級最高的非空隊列)。從
active->queue[i]
中取出第一個進程。將該進程投入運行。
當該進程的時間片用完,它會被從CPU上剝離。
調度器重新計算它的時間片和新優先級(可能根據其行為交互式還是計算型進行動態調整),然后將其放入
expired->queue[k]
中(k是計算出的新優先級)。重復步驟1-5,直到
active
隊列為空。比喻步驟:
經理查看電子指示屏,找到編號最小的、燈還亮著的掛鉤(比如101號)。
他走到101號掛鉤前,取下最前面的那個訂單,叫對應的廚師(比如廚師A)進廚房工作。
廚師A在廚房工作,直到經理喊“時間到!”。
廚師A出來,經理根據他剛才的表現(是一直在切菜(CPU密集型)還是經常等送食材(I/O密集型)),重新評估他的效率,并給他分配新的下次工作時間(重置時間片)。
然后經理把廚師A的訂單掛到 “等待換班”板 的對應優先級的掛鉤上(比如新優先級變成了105)。
經理繼續從“正在叫號”板叫下一個廚師。
隊列交換 🙃
理論:當
active
隊列完全為空時,調度器只需執行一個簡單的指針交換操作:swap(active, expired)
。之后,原來的過期隊列變成新的活動隊列,而空的活動隊列則成為新的過期隊列。比喻:當 “正在叫號”板 上的所有訂單都被處理完,變得空空如也時。經理并不慌張,他做了一件非常聰明的事:直接把“正在叫號”和“等待換班”兩塊白板的標簽互換!瞬間,滿是訂單的“等待換班”板變成了新的“正在叫號”板,而空的板子則成為了新的“等待換班”板。所有等待的廚師又都有了新的工作時間。
為什么叫O(1)算法?👌
理論:無論系統中有多少進程,查找下一個要運行的進程的時間都是一個常數。因為它不遍歷所有進程,而是通過查詢固定大小的
bitmap
(常數時間)和操作固定數量的隊列(140個)來完成。比喻:無論餐廳有多少等待的廚師,經理決定下一個叫誰的時間都是一樣的。他只需要看一眼固定大小的電子指示屏,而不是從頭到尾數一遍所有廚師。
總結🐷
了解了這么多,我們可以看到Linux調度器的設計之美:
-
效率:通過
bitmap
和雙隊列結構,將調度算法復雜度降為O(1)。 -
公平:通過時間片輪轉和優先級結合,保證所有進程都能得到執行,不會出現“饑餓”現象。
-
智能:調度器會根據進程的過去行為(I/O密集還是CPU密集)動態調整其優先級,讓交互式程序(如桌面點擊)響應更快,體驗更好。
???本篇博客內容結束,期待與各位優秀程序員交流,有什么問題請私信???
???如果這一篇博客對你有幫助~別忘了點贊分享哦~???
??????個人主頁??????