進(jìn)程調(diào)度簡(jiǎn)介
在linux中,進(jìn)程是最基本的執(zhí)行單位。進(jìn)程調(diào)度在整個(gè)操作系統(tǒng)中屬于核心地位,是操作系統(tǒng)實(shí)現(xiàn)多任務(wù)處理的關(guān)鍵操作,確保每個(gè)進(jìn)程在有限的cpu資源下有序的完成相應(yīng)操作。

在linux操作系統(tǒng)中,同一時(shí)間下不僅僅只有一個(gè)進(jìn)程在執(zhí)行任務(wù)而是多個(gè)進(jìn)程同時(shí)競(jìng)爭(zhēng)有限的CPU資源。若沒(méi)有進(jìn)程調(diào)度操作,整個(gè)系統(tǒng)可能會(huì)陷入混亂,例如你正在聽(tīng)著歌卻突然把歌停了給你播放視頻。因此,進(jìn)程調(diào)度尤為重要。
進(jìn)程調(diào)度的高效性會(huì)直接影響到系統(tǒng)的性能。一個(gè)高效的進(jìn)程調(diào)度算法能夠迅速完成大量進(jìn)程間的切換,從而確保CPU資源得到最大程度的利用。以輪轉(zhuǎn)調(diào)度(Round Robin, RR)算法為例,該算法將CPU時(shí)間分割成多個(gè)固定的時(shí)間片,每個(gè)進(jìn)程依次占用一個(gè)時(shí)間片進(jìn)行執(zhí)行。這種方式確保了所有進(jìn)程都能獲得一定的執(zhí)行時(shí)間,進(jìn)而提升了系統(tǒng)的整體處理能力。據(jù)統(tǒng)計(jì),在合理設(shè)定時(shí)間片長(zhǎng)度的情況下,輪轉(zhuǎn)調(diào)度算法能顯著提升系統(tǒng)吞吐量,增幅可達(dá)20%至30%。
公平性同樣是進(jìn)程調(diào)度中的一項(xiàng)關(guān)鍵考量。它要求每個(gè)進(jìn)程都能獲得適當(dāng)?shù)腃PU時(shí)間片,以防止某些進(jìn)程因長(zhǎng)時(shí)間無(wú)法執(zhí)行而陷入饑餓狀態(tài)。例如,在優(yōu)先級(jí)調(diào)度算法中,若高優(yōu)先級(jí)進(jìn)程持續(xù)不斷地產(chǎn)生,可能會(huì)導(dǎo)致低優(yōu)先級(jí)進(jìn)程長(zhǎng)時(shí)間得不到執(zhí)行機(jī)會(huì)。為解決這一問(wèn)題,可以采取老化等技術(shù)手段,逐步提高那些等待時(shí)間過(guò)長(zhǎng)的進(jìn)程的優(yōu)先級(jí)。
公平性也是進(jìn)程調(diào)度的重要目標(biāo)之一。每個(gè)進(jìn)程都應(yīng)該有機(jī)會(huì)獲得合理的 CPU 時(shí)間片,避免饑餓現(xiàn)象的發(fā)生。例如,優(yōu)先級(jí)調(diào)度算法中,如果源源不斷地產(chǎn)生高優(yōu)先級(jí)的進(jìn)程,那么低優(yōu)先級(jí)的進(jìn)程可能會(huì)長(zhǎng)時(shí)間得不到執(zhí)行。為了解決這個(gè)問(wèn)題,可以采用老化等技術(shù),逐漸增加等待很長(zhǎng)時(shí)間的進(jìn)程的優(yōu)先級(jí)。
1.2進(jìn)程查看命令 -e 或 –every:顯示系統(tǒng)中所有的進(jìn)程。 -f 或 –full:提供完整的格式輸出,包括進(jìn)程樹(shù)狀關(guān)系和環(huán)境變量等額外信息。 -l 或 –long:長(zhǎng)格式輸出,包含更多詳細(xì)信息,如F旗表示進(jìn)程正在等待文件鎖。 -u 或 –user:按照用戶來(lái)顯示進(jìn)程,并顯示每個(gè)進(jìn)程的CPU和內(nèi)存使用情況。 -aux 是一個(gè)常見(jiàn)的組合選項(xiàng),用于顯示系統(tǒng)中所有用戶的全部進(jìn)程,包括后臺(tái)進(jìn)程(不與終端關(guān)聯(lián)的進(jìn)程)。 進(jìn)程列表:按照默認(rèn)排序(通常是CPU使用率或優(yōu)先級(jí))列出正在運(yùn)行的進(jìn)程及其相關(guān)信息,如PID、USER(執(zhí)行進(jìn)程的用戶)、PR(優(yōu)先級(jí))、NI(nice值,影響優(yōu)先級(jí))、VIRT(虛擬內(nèi)存大小)、RES(常駐內(nèi)存大小)、%CPU和%MEM(CPU和內(nèi)存使用百分比)等。 系統(tǒng)總體狀態(tài):包括系統(tǒng)運(yùn)行時(shí)間、登錄用戶數(shù)、系統(tǒng)負(fù)載、CPU和內(nèi)存的整體使用狀況等統(tǒng)計(jì)數(shù)據(jù)。 交互式操作:在top運(yùn)行過(guò)程中,用戶可以通過(guò)鍵盤(pán)輸入相應(yīng)的命令(如按P鍵切換到按CPU使用率排序,按M鍵切換到按內(nèi)存使用率排序,或使用k鍵殺死指定進(jìn)程等)來(lái)進(jìn)行進(jìn)一步的進(jìn)程管理和監(jiān)控。
1.3進(jìn)程的幾個(gè)要素 有一段程序待其執(zhí)行 有進(jìn)程專(zhuān)用的系統(tǒng)堆棧空間 在內(nèi)核有task_struct結(jié)構(gòu)體 進(jìn)程有獨(dú)立的存儲(chǔ)空間,擁有專(zhuān)用的用戶空間
二、進(jìn)程的生命周期2.1進(jìn)程狀態(tài)文字描述
linux操作系統(tǒng)屬于多任務(wù)操作系統(tǒng),系統(tǒng)中的每個(gè)進(jìn)程能夠分時(shí)復(fù)用CPU時(shí)間片,通過(guò)有效的進(jìn)程調(diào)度策略實(shí)現(xiàn)多任務(wù)并行執(zhí)行。而進(jìn)程在被CPU調(diào)度運(yùn)行,等待CPU資源分配以及等待外部事件時(shí)會(huì)屬于不同的狀態(tài)。
共有五種狀態(tài):
創(chuàng)建狀態(tài):新進(jìn)程剛剛被創(chuàng)建,尚未開(kāi)始執(zhí)行。 就緒狀態(tài):進(jìn)程已準(zhǔn)備好所有必需資源,等待CPU分配時(shí)間片執(zhí)行。 執(zhí)行狀態(tài):進(jìn)程已獲得CPU資源并在其中運(yùn)行。 阻塞狀態(tài):進(jìn)程因等待某個(gè)資源或事件而暫時(shí)停止運(yùn)行,從CPU隊(duì)列中移除。 終止?fàn)顟B(tài):進(jìn)程已完成執(zhí)行或被終止,不再存在。
進(jìn)程狀態(tài)程序中的體現(xiàn):
代碼語(yǔ)言:JavaScript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
#define TASK_RUNNING0x00000000#define TASK_intERRUPTIBLE0x00000001#define TASK_UNINTERRUPTIBLE0x00000002#define __TASK_STOPPED0x00000004#define __TASK_TRACED0x00000008
TASK_RUNNING 表示進(jìn)程處于可運(yùn)行狀態(tài)。這意味著進(jìn)程已經(jīng)準(zhǔn)備好在CPU上執(zhí)行,并且調(diào)度器可以選擇它來(lái)進(jìn)行運(yùn)行。當(dāng)進(jìn)程獲取到CPU時(shí)間片時(shí),它就會(huì)進(jìn)入運(yùn)行狀態(tài)。 TASK_INTERRUPTIBLE 表示進(jìn)程處于可中斷睡眠狀態(tài)。這種狀態(tài)下,進(jìn)程正在等待某個(gè)事件發(fā)生(例如I/O操作完成、鎖可用等),并且如果收到信號(hào)或者等待的條件滿足,它可以被喚醒并重新加入到可運(yùn)行隊(duì)列中。在可中斷睡眠期間,進(jìn)程可以響應(yīng)信號(hào)并改變其狀態(tài)。 TASK_UNINTERRUPTIBLE 表示進(jìn)程處于不可中斷睡眠狀態(tài)。類(lèi)似可中斷睡眠,進(jìn)程同樣在等待某種資源或事件,但是在此狀態(tài)下,進(jìn)程不會(huì)響應(yīng)任何信號(hào),即使接收到信號(hào)也不會(huì)立即醒來(lái),除非等待的資源變?yōu)榭捎没蛱囟l件達(dá)成。 __TASK_STOPPED 標(biāo)志意味著進(jìn)程已停止執(zhí)行,通常是因?yàn)槭盏搅薙igsTOP或SIGTSTP這樣的停止信號(hào),或者是調(diào)試器暫停了進(jìn)程。停止的進(jìn)程不會(huì)消耗CPU資源,直到收到SIGCONT信號(hào)恢復(fù)執(zhí)行。 __TASK_TRACED 表示進(jìn)程正在被調(diào)試器或其他跟蹤工具追蹤,并進(jìn)入了跟蹤停止?fàn)顟B(tài)。在這種狀態(tài)下,進(jìn)程同樣不會(huì)執(zhí)行,等待調(diào)試器的進(jìn)一步操作,比如單步執(zhí)行、繼續(xù)執(zhí)行等。
這些狀態(tài)標(biāo)志會(huì)被組合在一個(gè)進(jìn)程控制塊(PCB,在Linux內(nèi)核中表現(xiàn)為task_struct結(jié)構(gòu)體的一個(gè)成員變量state)中,以表示進(jìn)程的當(dāng)前狀態(tài)。調(diào)度器根據(jù)這些狀態(tài)決定何時(shí)何地將進(jìn)程投入運(yùn)行或從運(yùn)行狀態(tài)移除。在實(shí)際的內(nèi)核源碼中,為了準(zhǔn)確反映進(jìn)程狀態(tài),這些宏可能會(huì)與其他標(biāo)志位一起使用或組合起來(lái)形成更復(fù)雜的狀態(tài)標(biāo)識(shí)。
2.2進(jìn)程狀態(tài)的切換
如下圖,便是進(jìn)程進(jìn)行狀態(tài)之間的切換,這些工作都是有調(diào)度器來(lái)完成的。

2.3task_struct數(shù)據(jù)結(jié)構(gòu)
進(jìn)程是操作系統(tǒng)調(diào)度的一個(gè)實(shí)體,需要對(duì)進(jìn)程所必須資源做一個(gè)抽象化,此抽象化為進(jìn)程控制塊 (PCB,Process Control BLock) ,PCB在Linux內(nèi)核里面采用task_struct結(jié)構(gòu)體來(lái)描述進(jìn)程控制塊。Linux內(nèi)核涉及進(jìn)程和程序的所有算法都圍繞名為task_struct的數(shù)據(jù)結(jié)構(gòu)而建立操作。具體Linux內(nèi)核源碼task_struct結(jié)構(gòu)體核心成員如下(task_struct結(jié)構(gòu)體過(guò)于龐大,暫時(shí)了解幾個(gè)重要成員)task_struct定義在includelinuxsched.h:
__state:表示當(dāng)前進(jìn)程狀態(tài),例如可運(yùn)行、睡眠、僵死等。 stack:指向進(jìn)程的內(nèi)核棧。 usage:引用計(jì)數(shù),用于跟蹤進(jìn)程使用情況。 prio、static_prio和normal_prio:描述進(jìn)程的調(diào)度優(yōu)先級(jí)和策略。 se、rt和dl:分別對(duì)應(yīng)CFS(完全公平調(diào)度器)、實(shí)時(shí)調(diào)度和Deadline調(diào)度的調(diào)度實(shí)體。 mm:指向進(jìn)程的內(nèi)存描述符結(jié)構(gòu)(mm_struct),管理進(jìn)程的虛擬內(nèi)存。 active_mm:在沒(méi)有獨(dú)立內(nèi)存空間時(shí),指向當(dāng)前活動(dòng)的內(nèi)存描述符。 exit_state、exit_code和exit_signal:進(jìn)程退出時(shí)的狀態(tài)、退出碼和發(fā)送給父進(jìn)程的信號(hào)。 pid和tgid:分別代表進(jìn)程ID和線程組ID。 real_parent、parent、children和sibling:用于構(gòu)建進(jìn)程間的父子、兄弟關(guān)系,形成進(jìn)程樹(shù)。 files:指向進(jìn)程打開(kāi)的文件表,即files_struct結(jié)構(gòu)體,記錄所有已打開(kāi)的文件描述符。 signal和sighand:管理和處理進(jìn)程接收到的信號(hào)。 blocked、real_blocked和saved_sigmask:記錄進(jìn)程當(dāng)前屏蔽的信號(hào)集合。 nsproxy:命名空間代理,用于管理和切換不同命名空間。 fs:指向文件系統(tǒng)信息結(jié)構(gòu),記錄進(jìn)程的當(dāng)前工作目錄、根目錄等文件系統(tǒng)相關(guān)信息。
其他字段還包括了進(jìn)程的調(diào)度統(tǒng)計(jì)信息、時(shí)間統(tǒng)計(jì)、內(nèi)存頁(yè)面錯(cuò)誤統(tǒng)計(jì)、POSIX定時(shí)器、安全特性、審計(jì)信息等。
2.4進(jìn)程優(yōu)先級(jí)⑴優(yōu)先級(jí)的代碼表示
描述進(jìn)程的調(diào)度優(yōu)先級(jí)和策略,之后的任務(wù)調(diào)度以及時(shí)間片分配都要用到優(yōu)先級(jí):
代碼語(yǔ)言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
intprio;intstatic_prio;intnormal_prio;unsigned intrt_priority;
int prio: 這個(gè)字段代表進(jìn)程的動(dòng)態(tài)優(yōu)先級(jí),它是根據(jù)進(jìn)程的行為和系統(tǒng)負(fù)載動(dòng)態(tài)調(diào)整的。在傳統(tǒng)的Linux調(diào)度器(如CFS調(diào)度器)中,這個(gè)優(yōu)先級(jí)通常被映射到調(diào)度實(shí)體(sched_entity)的一個(gè)虛擬運(yùn)行時(shí)間(vruntime),而不是一個(gè)直觀意義上的數(shù)字大小,較大的vruntime意味著較低的優(yōu)先級(jí)。 int static_prio: 靜態(tài)優(yōu)先級(jí),也稱為nice值,在Linux中范圍是-20至19,數(shù)值越小表示優(yōu)先級(jí)越高。靜態(tài)優(yōu)先級(jí)可以通過(guò)nice值或者用戶權(quán)限改變,但不會(huì)像動(dòng)態(tài)優(yōu)先級(jí)那樣頻繁變化。 int normal_prio: 此字段在某些Linux調(diào)度器實(shí)現(xiàn)中可能用來(lái)表示經(jīng)過(guò)nice值調(diào)整后的正常優(yōu)先級(jí),它結(jié)合了靜態(tài)優(yōu)先級(jí)和可能的額外優(yōu)先級(jí)調(diào)整因素。 unsigned int rt_priority: 實(shí)時(shí)優(yōu)先級(jí),僅適用于實(shí)時(shí)調(diào)度策略(如SCHED_FIFO或SCHED_RR)。實(shí)時(shí)進(jìn)程有固定的優(yōu)先級(jí)分配,rt_priority值越大,表示進(jìn)程的實(shí)時(shí)優(yōu)先級(jí)越高,搶占其他進(jìn)程的可能性也就越大。實(shí)時(shí)進(jìn)程一般不受nice值的影響,其優(yōu)先級(jí)高于普通進(jìn)程。在實(shí)時(shí)調(diào)度策略下,rt_priority用于確定進(jìn)程在實(shí)時(shí)進(jìn)程隊(duì)列中的相對(duì)位置。 ⑵Linux內(nèi)核下的進(jìn)程分類(lèi)
在Linux內(nèi)核中,進(jìn)程可以按照其調(diào)度需求和優(yōu)先級(jí)的不同分為不同的類(lèi)別,主要包括:
SCHED_FIFO:實(shí)時(shí)進(jìn)程中,優(yōu)先級(jí)高的進(jìn)程總是優(yōu)先執(zhí)行,一旦開(kāi)始運(yùn)行,除非進(jìn)程主動(dòng)放棄CPU(如阻塞等待I/O或睡眠),否則不會(huì)被優(yōu)先級(jí)相同或更低的其他進(jìn)程搶占。 SCHED_RR:同樣是實(shí)時(shí)進(jìn)程,但它在用完時(shí)間片后會(huì)重新加入隊(duì)列等待下一次調(diào)度,這樣可以保證在相同優(yōu)先級(jí)的實(shí)時(shí)進(jìn)程中實(shí)現(xiàn)時(shí)間片輪轉(zhuǎn)。 普通進(jìn)程(Normal Process):又稱為分時(shí)進(jìn)程,這類(lèi)進(jìn)程在Linux系統(tǒng)中遵循默認(rèn)的分時(shí)調(diào)度策略,如CFS(Completely Fair Scheduler)。它們按照各自權(quán)重(nice值)和虛擬運(yùn)行時(shí)間(vruntime)來(lái)獲取CPU時(shí)間片。nice值可以在[-20, 19]范圍內(nèi)調(diào)整,數(shù)值越小,優(yōu)先級(jí)越高,但總體來(lái)說(shuō),普通進(jìn)程之間是公平共享CPU資源的。 實(shí)時(shí)進(jìn)程(Real-time Process):實(shí)時(shí)進(jìn)程在滿足特定條件的情況下需要得到及時(shí)響應(yīng),具有更高的優(yōu)先級(jí)。Linux內(nèi)核提供兩種實(shí)時(shí)調(diào)度策略:SCHED_FIFO(先進(jìn)先出)和SCHED_RR(輪轉(zhuǎn)調(diào)度)。 ⑶優(yōu)先級(jí)的在不同類(lèi)型進(jìn)程的分配 限期進(jìn)程的優(yōu)先級(jí)是-1; 實(shí)時(shí)進(jìn)程的優(yōu)先級(jí)1-99,優(yōu)先級(jí)數(shù)值最大,表示優(yōu)先級(jí)越高; 普通進(jìn)程的靜態(tài)優(yōu)先級(jí)為: 100-139,優(yōu)先級(jí)數(shù)值越小,表示優(yōu)先級(jí)越高,可通過(guò)修改nice值改變普通進(jìn)程的優(yōu)先級(jí),優(yōu)先級(jí)等于120加 上nice值;
2.5進(jìn)程調(diào)度的重要性⑴提升系統(tǒng)性能
進(jìn)程調(diào)度對(duì)系統(tǒng)性能的提升起著關(guān)鍵作用。通過(guò)合理地分配 CPU 資源,進(jìn)程調(diào)度可以極大地提高 CPU 利用率。例如,在完全公平調(diào)度器(CFS)中,根據(jù)進(jìn)程的虛擬運(yùn)行時(shí)間來(lái)分配 CPU 時(shí)間,確保每個(gè)進(jìn)程都能獲得相對(duì)公平的執(zhí)行機(jī)會(huì),從而有效提高 CPU 的利用率。據(jù)統(tǒng)計(jì),采用 CFS 的系統(tǒng)中,CPU 利用率可以提高 15% 至 20%。
系統(tǒng)吞吐量是衡量系統(tǒng)性能的另一個(gè)重要指標(biāo)。良好的進(jìn)程調(diào)度算法可以在單位時(shí)間內(nèi)完成更多的進(jìn)程,從而提高系統(tǒng)吞吐量。以多級(jí)反饋隊(duì)列調(diào)度為例,它將就緒隊(duì)列分成多個(gè)優(yōu)先級(jí)不同的隊(duì)列,每個(gè)隊(duì)列采用不同的調(diào)度算法。短作業(yè)可以在高優(yōu)先級(jí)隊(duì)列中快速得到執(zhí)行,而長(zhǎng)作業(yè)則在低優(yōu)先級(jí)隊(duì)列中逐步執(zhí)行,這樣可以兼顧不同類(lèi)型進(jìn)程的需求,提高系統(tǒng)的整體吞吐量。實(shí)驗(yàn)表明,使用多級(jí)反饋隊(duì)列調(diào)度的系統(tǒng),吞吐量可以比傳統(tǒng)的先來(lái)先服務(wù)調(diào)度提高 30% 至 40%。
此外,進(jìn)程調(diào)度還可以降低周轉(zhuǎn)時(shí)間、等待時(shí)間和響應(yīng)時(shí)間。周轉(zhuǎn)時(shí)間是指進(jìn)程從提交到完成所花費(fèi)的時(shí)間,等待時(shí)間是進(jìn)程在就緒隊(duì)列中等待的時(shí)間,響應(yīng)時(shí)間是從進(jìn)程提交到首次獲得 CPU 時(shí)間的時(shí)間間隔。通過(guò)合理的調(diào)度算法,如短作業(yè)優(yōu)先調(diào)度,可以優(yōu)先執(zhí)行短作業(yè),減少這些時(shí)間指標(biāo)。研究顯示,在特定的工作負(fù)載下,短作業(yè)優(yōu)先調(diào)度可以將平均周轉(zhuǎn)時(shí)間降低 20% 至 30%,響應(yīng)時(shí)間降低 15% 至 20%。
⑵確保公平性
公平性是進(jìn)程調(diào)度的核心目標(biāo)之一。為了避免進(jìn)程饑餓現(xiàn)象,各種調(diào)度算法都采取了不同的措施。在優(yōu)先級(jí)調(diào)度中,雖然高優(yōu)先級(jí)的進(jìn)程會(huì)優(yōu)先獲得 CPU 資源,但為了防止低優(yōu)先級(jí)進(jìn)程長(zhǎng)時(shí)間得不到執(zhí)行,可以采用動(dòng)態(tài)調(diào)整優(yōu)先級(jí)的方法。例如,隨著低優(yōu)先級(jí)進(jìn)程的等待時(shí)間增加,逐漸提高其優(yōu)先級(jí),使其有機(jī)會(huì)獲得 CPU 執(zhí)行時(shí)間。
同時(shí),一些調(diào)度算法還通過(guò)限制高優(yōu)先級(jí)進(jìn)程的執(zhí)行時(shí)間來(lái)確保公平性。例如,在實(shí)時(shí)調(diào)度中,硬實(shí)時(shí)任務(wù)雖然要求在嚴(yán)格的時(shí)間限制內(nèi)完成,但也不能無(wú)限占用 CPU 資源。調(diào)度算法會(huì)在保證硬實(shí)時(shí)任務(wù)按時(shí)完成的前提下,合理分配 CPU 時(shí)間給其他進(jìn)程,以實(shí)現(xiàn)系統(tǒng)的整體公平性。
三、進(jìn)程系統(tǒng)調(diào)用3.1系統(tǒng)調(diào)用函數(shù)
當(dāng)運(yùn)行應(yīng)用程序的時(shí)候,調(diào)用fork()/vfork()/clone()函數(shù)就是系統(tǒng)調(diào)用。系統(tǒng)調(diào)用就是應(yīng)用程序如何進(jìn)入內(nèi)核空間執(zhí)行任務(wù),程序使用系統(tǒng)調(diào)用執(zhí)行一系列的操作: 比如創(chuàng)建進(jìn)程、文件IO等等。
系統(tǒng)調(diào)用框圖(使用Linux版本為6.1的內(nèi)核,不同的內(nèi)核其系統(tǒng)調(diào)用有點(diǎn)差異) 如下所示:

⑴fork系統(tǒng)調(diào)用代碼代碼語(yǔ)言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
#ifdef __ARCH_WANT_SYS_FORKSYSCALL_DEFINE0(fork){#ifdef CONFIG_MMUstruct kernel_clone_args args = {.exit_signal = SIGCHLD,}; return kernel_clone(&args);#else/* can not support in nommu mode */return -EINVAL;#endif}
⑵vfork系統(tǒng)調(diào)用代碼代碼語(yǔ)言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
#ifdef __ARCH_WANT_SYS_VFORKSYSCALL_DEFINE0(vfork){struct kernel_clone_args args = {.flags= CLONE_VFORK | CLONE_VM,.exit_signal= SIGCHLD,}; return kernel_clone(&args);}#endif
⑶clone系統(tǒng)調(diào)用代碼代碼語(yǔ)言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
#ifdef __ARCH_WANT_SYS_CLONE#ifdef CONFIG_CLONE_BACKWARDSSYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, int __user *, parent_tidptr, unsigned long, tls, int __user *, child_tidptr)#elif defined(CONFIG_CLONE_BACKWARDS2)SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags, int __user *, parent_tidptr, int __user *, child_tidptr, unsigned long, tls)#elif defined(CONFIG_CLONE_BACKWARDS3)SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,int, stack_size,int __user *, parent_tidptr,int __user *, child_tidptr,unsigned long, tls)#elseSYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, int __user *, parent_tidptr, int __user *, child_tidptr, unsigned long, tls)#endif{struct kernel_clone_args args = {.flags= (lower_32_bits(clone_flags) & ~CSIGNAL),.pidfd= parent_tidptr,.child_tid= child_tidptr,.parent_tid= parent_tidptr,.exit_signal= (lower_32_bits(clone_flags) & CSIGNAL),.stack= newsp,.tls= tls,}; return kernel_clone(&args);}#endif
⑷進(jìn)程退出
①、進(jìn)程主動(dòng)終止: 從main()函數(shù)返回,鏈接程序會(huì)自動(dòng)添加到exit()系統(tǒng)調(diào)用; exit系統(tǒng)調(diào)用在內(nèi)核定義如下kernelexit.c:
代碼語(yǔ)言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
SYSCALL_DEFINE1(exit, int, error_code){do_exit((error_code&0xff)<p>②、進(jìn)程被動(dòng)終止: 進(jìn)程收到一個(gè)自己不能處理的信號(hào);進(jìn)程收到 SIGKILL等終止信息。</p>⑸內(nèi)核線程<p> 定義:它是獨(dú)立運(yùn)行在內(nèi)核空間的進(jìn)程,與普通用戶進(jìn)程區(qū)別在于內(nèi)核線程沒(méi)有獨(dú)立的進(jìn)程地址空間。task_struct數(shù)據(jù)結(jié)構(gòu)里面有一個(gè)成員指針mm設(shè)置為NULL,它只能運(yùn)行在內(nèi)核空間。內(nèi)核創(chuàng)建一個(gè)內(nèi)核線程代碼體現(xiàn)如下:</p>代碼語(yǔ)言:javascript<i class="icon-code"></i>代碼運(yùn)行次數(shù):<!-- -->0<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewbox="0 0 16 16" fill="none"><path d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>運(yùn)行<svg width="16" height="16" viewbox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor"></path></svg>復(fù)制<pre class="prism-token token line-numbers javascript">/* * Create a kernel thread. */pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags){struct kernel_clone_args args = {.flags= ((lower_32_bits(flags) | CLONE_VM | CLONE_UNTRACED) & ~CSIGNAL),.exit_signal= (lower_32_bits(flags) & CSIGNAL),.fn= fn,.fn_arg= arg,.kthread= 1,}; return kernel_clone(&args);}
3.2常見(jiàn)的進(jìn)程調(diào)度算法⑴先來(lái)先服務(wù)(FCFS)
先來(lái)先服務(wù)調(diào)度算法是一種最簡(jiǎn)單的調(diào)度算法,它按照進(jìn)程到達(dá)的先后順序進(jìn)行調(diào)度。當(dāng)一個(gè)進(jìn)程進(jìn)入就緒隊(duì)列時(shí),它會(huì)按照到達(dá)的順序排隊(duì)等待 CPU 的分配。這種算法的優(yōu)點(diǎn)是實(shí)現(xiàn)簡(jiǎn)單,公平性較高,每個(gè)進(jìn)程都按照其到達(dá)的順序依次獲得 CPU 時(shí)間。然而,它也存在明顯的缺點(diǎn)。對(duì)于長(zhǎng)進(jìn)程來(lái)說(shuō),可能會(huì)長(zhǎng)時(shí)間占用 CPU,導(dǎo)致后續(xù)到達(dá)的短進(jìn)程和 I/O 繁忙型作業(yè)等待時(shí)間過(guò)長(zhǎng)。例如,假設(shè)有三個(gè)進(jìn)程 P1、P2 和 P3,P1 的執(zhí)行時(shí)間為 30 秒,P2 的執(zhí)行時(shí)間為 5 秒,P3 的執(zhí)行時(shí)間為 20 秒。如果按照先來(lái)先服務(wù)的算法調(diào)度,P1 先執(zhí)行,那么 P2 和 P3 就需要等待 30 秒后才能開(kāi)始執(zhí)行,這大大增加了短進(jìn)程和 I/O 繁忙型作業(yè)的等待時(shí)間,降低了系統(tǒng)的整體效率。
⑵短作業(yè)優(yōu)先(SJF)
短作業(yè)優(yōu)先調(diào)度算法優(yōu)先調(diào)度執(zhí)行時(shí)間最短的進(jìn)程。這種算法的目的是減少平均等待時(shí)間,提高系統(tǒng)的吞吐量。然而,它也存在一些問(wèn)題。首先,它可能導(dǎo)致長(zhǎng)作業(yè)饑餓,因?yàn)殚L(zhǎng)作業(yè)可能一直等待短作業(yè)執(zhí)行完畢后才能獲得 CPU 時(shí)間。其次,準(zhǔn)確估計(jì)作業(yè)的執(zhí)行時(shí)間是非常困難的。在實(shí)際應(yīng)用中,程序員很難準(zhǔn)確估計(jì)作業(yè)的執(zhí)行時(shí)間,通常會(huì)偏長(zhǎng)估計(jì),這可能導(dǎo)致算法的效果不如預(yù)期。例如,如果有一個(gè)長(zhǎng)作業(yè)需要執(zhí)行 100 秒,而不斷有短作業(yè)到來(lái),那么長(zhǎng)作業(yè)可能永遠(yuǎn)也得不到調(diào)度,從而出現(xiàn)饑餓現(xiàn)象。
⑶優(yōu)先級(jí)調(diào)度
優(yōu)先級(jí)調(diào)度算法根據(jù)進(jìn)程的優(yōu)先級(jí)進(jìn)行調(diào)度。每個(gè)進(jìn)程都被賦予一個(gè)優(yōu)先級(jí),優(yōu)先級(jí)高的進(jìn)程優(yōu)先獲得 CPU 時(shí)間。這種算法可以根據(jù)進(jìn)程的重要性或緊急程度來(lái)分配 CPU 資源,具有一定的靈活性。但是,它也可能導(dǎo)致低優(yōu)先級(jí)進(jìn)程饑餓。如果不斷有高優(yōu)先級(jí)進(jìn)程到來(lái),低優(yōu)先級(jí)進(jìn)程可能長(zhǎng)時(shí)間得不到執(zhí)行。靜態(tài)優(yōu)先級(jí)調(diào)度在進(jìn)程創(chuàng)建時(shí)分配優(yōu)先級(jí),并在整個(gè)執(zhí)行過(guò)程中保持不變;動(dòng)態(tài)優(yōu)先級(jí)調(diào)度則根據(jù)進(jìn)程的行為和狀態(tài)動(dòng)態(tài)調(diào)整優(yōu)先級(jí)。例如,在一些實(shí)時(shí)系統(tǒng)中,緊急任務(wù)被賦予高優(yōu)先級(jí),以確保它們能夠及時(shí)得到處理。但是,如果高優(yōu)先級(jí)任務(wù)過(guò)多,低優(yōu)先級(jí)任務(wù)可能會(huì)被長(zhǎng)時(shí)間忽略。
⑷輪轉(zhuǎn)調(diào)度(RR)
輪轉(zhuǎn)調(diào)度算法將 CPU 時(shí)間分成固定大小的時(shí)間片,所有進(jìn)程輪流獲得一個(gè)時(shí)間片的 CPU 使用權(quán)。這種算法具有較好的公平性,每個(gè)進(jìn)程都能在一定時(shí)間內(nèi)獲得 CPU 時(shí)間。然而,時(shí)間片的大小對(duì)系統(tǒng)性能有很大影響。如果時(shí)間片太小,會(huì)導(dǎo)致進(jìn)程切換頻繁,增加系統(tǒng)開(kāi)銷(xiāo);如果時(shí)間片太大,輪轉(zhuǎn)調(diào)度算法就會(huì)退化為先來(lái)先服務(wù)算法。此外,輪轉(zhuǎn)調(diào)度算法不利于處理緊急作業(yè),因?yàn)槊總€(gè)進(jìn)程都需要等待輪到自己才能獲得 CPU 時(shí)間。例如,假設(shè)有一個(gè)緊急任務(wù)需要立即執(zhí)行,但按照輪轉(zhuǎn)調(diào)度算法,它可能需要等待很長(zhǎng)時(shí)間才能獲得 CPU 時(shí)間。
⑸多級(jí)反饋隊(duì)列調(diào)度
多級(jí)反饋隊(duì)列調(diào)度算法結(jié)合了多種調(diào)度策略,根據(jù)進(jìn)程的特性將其分配到不同的隊(duì)列中,每個(gè)隊(duì)列采用不同的調(diào)度算法。這種算法具有較高的靈活性,可以適應(yīng)不同類(lèi)型的進(jìn)程。例如,高優(yōu)先級(jí)的短作業(yè)可以分配到高優(yōu)先級(jí)隊(duì)列中,采用短作業(yè)優(yōu)先調(diào)度算法;長(zhǎng)作業(yè)可以分配到低優(yōu)先級(jí)隊(duì)列中,采用先來(lái)先服務(wù)調(diào)度算法。然而,這種算法相對(duì)復(fù)雜,需要維護(hù)多個(gè)隊(duì)列,增加了系統(tǒng)的開(kāi)銷(xiāo)和管理難度。
⑹高響應(yīng)比優(yōu)先調(diào)度算法
高響應(yīng)比優(yōu)先調(diào)度算法權(quán)衡了短作業(yè)和長(zhǎng)作業(yè),兼顧了等待時(shí)間和執(zhí)行時(shí)間。響應(yīng)比是等待時(shí)間與執(zhí)行時(shí)間的比值,響應(yīng)比高的進(jìn)程優(yōu)先獲得 CPU 時(shí)間。這種算法既照顧了短作業(yè),又考慮了作業(yè)到達(dá)的先后次序,不會(huì)使長(zhǎng)作業(yè)長(zhǎng)期得不到服務(wù)。但是,計(jì)算響應(yīng)比會(huì)增加系統(tǒng)開(kāi)銷(xiāo),因?yàn)槊看握{(diào)度都需要計(jì)算每個(gè)進(jìn)程的響應(yīng)比。例如,在一個(gè)有多個(gè)進(jìn)程等待調(diào)度的系統(tǒng)中,計(jì)算響應(yīng)比需要消耗一定的時(shí)間和計(jì)算資源。
四、進(jìn)程調(diào)度的實(shí)現(xiàn)與優(yōu)化4.1調(diào)度算法的選擇
不同的場(chǎng)景和需求對(duì)進(jìn)程調(diào)度算法有著不同的要求。在批處理系統(tǒng)中,主要追求高吞吐量和系統(tǒng)資源的充分利用。例如,短作業(yè)優(yōu)先算法可以在一定程度上提高批處理系統(tǒng)的效率,因?yàn)樗鼉?yōu)先處理執(zhí)行時(shí)間短的作業(yè),從而在單位時(shí)間內(nèi)可以完成更多的作業(yè)。據(jù)統(tǒng)計(jì),在一些大型數(shù)據(jù)處理中心采用短作業(yè)優(yōu)先算法,系統(tǒng)吞吐量可以提高 15% 至 20%。
對(duì)于交互式系統(tǒng),響應(yīng)時(shí)間是關(guān)鍵指標(biāo)。此時(shí),輪轉(zhuǎn)調(diào)度算法可能更為合適,因?yàn)樗梢源_保每個(gè)進(jìn)程都能在較短的時(shí)間內(nèi)獲得 CPU 時(shí)間,從而提高系統(tǒng)的響應(yīng)速度。例如,在圖形用戶界面環(huán)境下,用戶期望每個(gè)操作都能得到及時(shí)的反饋,輪轉(zhuǎn)調(diào)度算法可以保證各個(gè)進(jìn)程輪流執(zhí)行,使得用戶操作不會(huì)被長(zhǎng)時(shí)間阻塞。
而在實(shí)時(shí)系統(tǒng)中,滿足截止時(shí)間是最重要的目標(biāo)。實(shí)時(shí)系統(tǒng)通常采用搶占式調(diào)度算法,如實(shí)時(shí)優(yōu)先級(jí)調(diào)度,確保緊急任務(wù)能夠在規(guī)定的時(shí)間內(nèi)得到處理。例如,在飛機(jī)飛行控制系統(tǒng)中,對(duì)響應(yīng)時(shí)間的要求極為嚴(yán)格,任何延遲都可能導(dǎo)致嚴(yán)重后果,實(shí)時(shí)優(yōu)先級(jí)調(diào)度算法可以確保關(guān)鍵任務(wù)優(yōu)先執(zhí)行。
4.2調(diào)度器的設(shè)計(jì)與實(shí)現(xiàn)
調(diào)度器的設(shè)計(jì)通常采用模塊化的方式,以便于適應(yīng)不同的系統(tǒng)需求和優(yōu)化目標(biāo)。以 Linux 的 CFS(完全公平調(diào)度器)為例,它通過(guò)為每個(gè)進(jìn)程安排一個(gè)虛擬運(yùn)行時(shí)鐘 vruntime,實(shí)現(xiàn)了公平性。當(dāng)一個(gè)進(jìn)程得以執(zhí)行時(shí),vruntime 的值不斷增大,而沒(méi)有運(yùn)行的進(jìn)程的 vruntime 保持不變。調(diào)度器總是選擇 vruntime 最小的進(jìn)程執(zhí)行,從而確保每個(gè)進(jìn)程都能獲得相對(duì)公平的 CPU 時(shí)間。
CFS 的設(shè)計(jì)思路簡(jiǎn)單而有效,它根據(jù)每個(gè)進(jìn)程的權(quán)重分配運(yùn)行時(shí)間。例如,假設(shè)有兩個(gè)進(jìn)程 A 和 B,權(quán)重分別為 1 和 2,調(diào)度周期為 30ms。那么進(jìn)程 A 的運(yùn)行時(shí)間是 30*(1)/(1+2)=10ms,進(jìn)程 B 的運(yùn)行時(shí)間是 30*(2)/(1+2)=20ms。同時(shí),CFS 通過(guò)調(diào)整 vruntime 的增長(zhǎng)速度來(lái)體現(xiàn)不同進(jìn)程的優(yōu)先級(jí),優(yōu)先級(jí)高的進(jìn)程 vruntime 增長(zhǎng)得較慢,從而獲得更多的運(yùn)行機(jī)會(huì)。
為了降低調(diào)度延遲帶來(lái)的不公平性,CFS 采用了紅黑樹(shù)數(shù)據(jù)結(jié)構(gòu)來(lái)管理就緒隊(duì)列。紅黑樹(shù)可以快速地找到 vruntime 最小的進(jìn)程,從而減少調(diào)度時(shí)間。此外,CFS 還支持按組來(lái)分配時(shí)間片,通過(guò) cgroup 機(jī)制,可以將 CPU 資源劃分為不同的組,以便更好地滿足不同應(yīng)用場(chǎng)景的需求。
4.3進(jìn)程狀態(tài)的轉(zhuǎn)換機(jī)制
進(jìn)程在其生命周期內(nèi)會(huì)經(jīng)歷多種狀態(tài)的轉(zhuǎn)換,這些轉(zhuǎn)換受到資源分配的影響。例如,當(dāng)一個(gè)進(jìn)程從創(chuàng)建態(tài)轉(zhuǎn)變?yōu)榫途w態(tài)時(shí),它需要獲得除 CPU 以外的所有必要資源。一旦這些資源分配完成,進(jìn)程就處于就緒狀態(tài),等待 CPU 的分配。
當(dāng)進(jìn)程獲得 CPU 資源并開(kāi)始執(zhí)行時(shí),它處于運(yùn)行態(tài)。然而,在運(yùn)行過(guò)程中,進(jìn)程可能會(huì)因?yàn)榈却硞€(gè)事件(如等待 I/O 操作完成、等待資源分配等)而進(jìn)入等待態(tài)。在等待態(tài)下,進(jìn)程會(huì)被暫時(shí)掛起,以釋放 CPU 資源供其他進(jìn)程使用。當(dāng)?shù)却氖录l(fā)生時(shí),進(jìn)程會(huì)被喚醒并重新進(jìn)入就緒態(tài)。
此外,進(jìn)程還可能因?yàn)闀r(shí)間片用完或被更高優(yōu)先級(jí)的進(jìn)程搶占 CPU 而從運(yùn)行態(tài)回到就緒態(tài)。而當(dāng)一個(gè)進(jìn)程完成其任務(wù)或出現(xiàn)無(wú)法克服的錯(cuò)誤時(shí),它會(huì)進(jìn)入終止態(tài),等待操作系統(tǒng)進(jìn)行善后處理。
學(xué)習(xí)編程就得循環(huán)漸進(jìn),扎實(shí)基礎(chǔ),勿在浮沙筑高臺(tái)