Linux 支持多種調(diào)度策略(如 SCHED_OTHER、SCHED_FIFO、SCHED_RR、SCHED_DEADLINE),那 CPU 輪轉(zhuǎn)(調(diào)度)時(shí),內(nèi)核是如何選擇用哪個(gè)策略的?
1. 調(diào)度器的“分層”選擇機(jī)制
Linux 調(diào)度器采用分層優(yōu)先級(jí)的方式來(lái)管理不同策略的進(jìn)程:
A. 實(shí)時(shí)優(yōu)先,普通次之
-
實(shí)時(shí)進(jìn)程(SCHED_FIFO、SCHED_RR、SCHED_DEADLINE)
- 優(yōu)先級(jí)最高。只要有可運(yùn)行的實(shí)時(shí)進(jìn)程,調(diào)度器一定優(yōu)先調(diào)度實(shí)時(shí)進(jìn)程。
- 多個(gè)實(shí)時(shí)進(jìn)程之間,再根據(jù)各自的策略和優(yōu)先級(jí)排序。
-
普通進(jìn)程(SCHED_OTHER、SCHED_BATCH、SCHED_IDLE)
- 只有在沒(méi)有可運(yùn)行的實(shí)時(shí)進(jìn)程時(shí),調(diào)度器才會(huì)選擇普通進(jìn)程。
- 普通進(jìn)程之間再用 CFS(完全公平調(diào)度器)等算法排序。
2. 調(diào)度器的選擇流程(簡(jiǎn)化版)
每當(dāng)需要調(diào)度(比如時(shí)間片用完、進(jìn)程阻塞/喚醒、系統(tǒng)調(diào)用等),調(diào)度器會(huì):
-
檢查所有可運(yùn)行的實(shí)時(shí)進(jìn)程隊(duì)列
- 如果有 SCHED_DEADLINE 進(jìn)程,先選 deadline 最早的。
- 否則,檢查 SCHED_FIFO/SCHED_RR 隊(duì)列,按優(yōu)先級(jí)(1~99)從高到低選擇。
- SCHED_FIFO:同優(yōu)先級(jí)下先到先服務(wù),直到主動(dòng)讓出 CPU。
- SCHED_RR:同優(yōu)先級(jí)下輪流分配時(shí)間片。
-
如果沒(méi)有可運(yùn)行的實(shí)時(shí)進(jìn)程
- 選擇普通進(jìn)程隊(duì)列(CFS),按 vruntime(虛擬運(yùn)行時(shí)間)最小的進(jìn)程調(diào)度。
- SCHED_BATCH、SCHED_IDLE 進(jìn)程優(yōu)先級(jí)更低,只有系統(tǒng)空閑時(shí)才會(huì)被調(diào)度。
3. 多核系統(tǒng)的情況
- 每個(gè) CPU 都有自己的就緒隊(duì)列,但調(diào)度器的選擇邏輯是一樣的。
- 進(jìn)程可以在不同 CPU 之間遷移,調(diào)度器會(huì)做負(fù)載均衡。
4. 源碼入口
- 主要在
kernel/sched/core.c的pick_next_task()函數(shù)。 - 偽代碼邏輯如下:
if (有可運(yùn)行的 SCHED_DEADLINE 進(jìn)程)
選 deadline 最早的
else if (有可運(yùn)行的 SCHED_FIFO/SCHED_RR 進(jìn)程)
選優(yōu)先級(jí)最高的實(shí)時(shí)進(jìn)程
else
選 CFS 隊(duì)列中 vruntime 最小的普通進(jìn)程
5. 總結(jié)
CPU 輪轉(zhuǎn)時(shí),Linux 調(diào)度器總是優(yōu)先選擇實(shí)時(shí)策略(SCHED_DEADLINE > SCHED_FIFO/RR)的進(jìn)程。如果沒(méi)有實(shí)時(shí)進(jìn)程,才會(huì)選擇普通策略(SCHED_OTHER/CFS)的進(jìn)程。每種策略內(nèi)部再按各自規(guī)則排序。