進程調度簡介
在linux中,進程是最基本的執行單位。進程調度在整個操作系統中屬于核心地位,是操作系統實現多任務處理的關鍵操作,確保每個進程在有限的cpu資源下有序的完成相應操作。

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

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

⑴fork系統調用代碼代碼語言:javascript代碼運行次數:0運行復制
#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系統調用代碼代碼語言:javascript代碼運行次數:0運行復制
#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系統調用代碼代碼語言:javascript代碼運行次數:0運行復制
#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
⑷進程退出
①、進程主動終止: 從main()函數返回,鏈接程序會自動添加到exit()系統調用; exit系統調用在內核定義如下kernelexit.c:
代碼語言:javascript代碼運行次數:0運行復制
SYSCALL_DEFINE1(exit, int, error_code){do_exit((error_code&0xff)<p>②、進程被動終止: 進程收到一個自己不能處理的信號;進程收到 SIGKILL等終止信息。</p>⑸內核線程<p> 定義:它是獨立運行在內核空間的進程,與普通用戶進程區別在于內核線程沒有獨立的進程地址空間。task_struct數據結構里面有一個成員指針mm設置為NULL,它只能運行在內核空間。內核創建一個內核線程代碼體現如下:</p>代碼語言:javascript<i class="icon-code"></i>代碼運行次數:<!-- -->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>運行<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>復制<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常見的進程調度算法⑴先來先服務(FCFS)
先來先服務調度算法是一種最簡單的調度算法,它按照進程到達的先后順序進行調度。當一個進程進入就緒隊列時,它會按照到達的順序排隊等待 CPU 的分配。這種算法的優點是實現簡單,公平性較高,每個進程都按照其到達的順序依次獲得 CPU 時間。然而,它也存在明顯的缺點。對于長進程來說,可能會長時間占用 CPU,導致后續到達的短進程和 I/O 繁忙型作業等待時間過長。例如,假設有三個進程 P1、P2 和 P3,P1 的執行時間為 30 秒,P2 的執行時間為 5 秒,P3 的執行時間為 20 秒。如果按照先來先服務的算法調度,P1 先執行,那么 P2 和 P3 就需要等待 30 秒后才能開始執行,這大大增加了短進程和 I/O 繁忙型作業的等待時間,降低了系統的整體效率。
⑵短作業優先(SJF)
短作業優先調度算法優先調度執行時間最短的進程。這種算法的目的是減少平均等待時間,提高系統的吞吐量。然而,它也存在一些問題。首先,它可能導致長作業饑餓,因為長作業可能一直等待短作業執行完畢后才能獲得 CPU 時間。其次,準確估計作業的執行時間是非常困難的。在實際應用中,程序員很難準確估計作業的執行時間,通常會偏長估計,這可能導致算法的效果不如預期。例如,如果有一個長作業需要執行 100 秒,而不斷有短作業到來,那么長作業可能永遠也得不到調度,從而出現饑餓現象。
⑶優先級調度
優先級調度算法根據進程的優先級進行調度。每個進程都被賦予一個優先級,優先級高的進程優先獲得 CPU 時間。這種算法可以根據進程的重要性或緊急程度來分配 CPU 資源,具有一定的靈活性。但是,它也可能導致低優先級進程饑餓。如果不斷有高優先級進程到來,低優先級進程可能長時間得不到執行。靜態優先級調度在進程創建時分配優先級,并在整個執行過程中保持不變;動態優先級調度則根據進程的行為和狀態動態調整優先級。例如,在一些實時系統中,緊急任務被賦予高優先級,以確保它們能夠及時得到處理。但是,如果高優先級任務過多,低優先級任務可能會被長時間忽略。
⑷輪轉調度(RR)
輪轉調度算法將 CPU 時間分成固定大小的時間片,所有進程輪流獲得一個時間片的 CPU 使用權。這種算法具有較好的公平性,每個進程都能在一定時間內獲得 CPU 時間。然而,時間片的大小對系統性能有很大影響。如果時間片太小,會導致進程切換頻繁,增加系統開銷;如果時間片太大,輪轉調度算法就會退化為先來先服務算法。此外,輪轉調度算法不利于處理緊急作業,因為每個進程都需要等待輪到自己才能獲得 CPU 時間。例如,假設有一個緊急任務需要立即執行,但按照輪轉調度算法,它可能需要等待很長時間才能獲得 CPU 時間。
⑸多級反饋隊列調度
多級反饋隊列調度算法結合了多種調度策略,根據進程的特性將其分配到不同的隊列中,每個隊列采用不同的調度算法。這種算法具有較高的靈活性,可以適應不同類型的進程。例如,高優先級的短作業可以分配到高優先級隊列中,采用短作業優先調度算法;長作業可以分配到低優先級隊列中,采用先來先服務調度算法。然而,這種算法相對復雜,需要維護多個隊列,增加了系統的開銷和管理難度。
⑹高響應比優先調度算法
高響應比優先調度算法權衡了短作業和長作業,兼顧了等待時間和執行時間。響應比是等待時間與執行時間的比值,響應比高的進程優先獲得 CPU 時間。這種算法既照顧了短作業,又考慮了作業到達的先后次序,不會使長作業長期得不到服務。但是,計算響應比會增加系統開銷,因為每次調度都需要計算每個進程的響應比。例如,在一個有多個進程等待調度的系統中,計算響應比需要消耗一定的時間和計算資源。
四、進程調度的實現與優化4.1調度算法的選擇
不同的場景和需求對進程調度算法有著不同的要求。在批處理系統中,主要追求高吞吐量和系統資源的充分利用。例如,短作業優先算法可以在一定程度上提高批處理系統的效率,因為它優先處理執行時間短的作業,從而在單位時間內可以完成更多的作業。據統計,在一些大型數據處理中心采用短作業優先算法,系統吞吐量可以提高 15% 至 20%。
對于交互式系統,響應時間是關鍵指標。此時,輪轉調度算法可能更為合適,因為它可以確保每個進程都能在較短的時間內獲得 CPU 時間,從而提高系統的響應速度。例如,在圖形用戶界面環境下,用戶期望每個操作都能得到及時的反饋,輪轉調度算法可以保證各個進程輪流執行,使得用戶操作不會被長時間阻塞。
而在實時系統中,滿足截止時間是最重要的目標。實時系統通常采用搶占式調度算法,如實時優先級調度,確保緊急任務能夠在規定的時間內得到處理。例如,在飛機飛行控制系統中,對響應時間的要求極為嚴格,任何延遲都可能導致嚴重后果,實時優先級調度算法可以確保關鍵任務優先執行。
4.2調度器的設計與實現
調度器的設計通常采用模塊化的方式,以便于適應不同的系統需求和優化目標。以 Linux 的 CFS(完全公平調度器)為例,它通過為每個進程安排一個虛擬運行時鐘 vruntime,實現了公平性。當一個進程得以執行時,vruntime 的值不斷增大,而沒有運行的進程的 vruntime 保持不變。調度器總是選擇 vruntime 最小的進程執行,從而確保每個進程都能獲得相對公平的 CPU 時間。
CFS 的設計思路簡單而有效,它根據每個進程的權重分配運行時間。例如,假設有兩個進程 A 和 B,權重分別為 1 和 2,調度周期為 30ms。那么進程 A 的運行時間是 30*(1)/(1+2)=10ms,進程 B 的運行時間是 30*(2)/(1+2)=20ms。同時,CFS 通過調整 vruntime 的增長速度來體現不同進程的優先級,優先級高的進程 vruntime 增長得較慢,從而獲得更多的運行機會。
為了降低調度延遲帶來的不公平性,CFS 采用了紅黑樹數據結構來管理就緒隊列。紅黑樹可以快速地找到 vruntime 最小的進程,從而減少調度時間。此外,CFS 還支持按組來分配時間片,通過 cgroup 機制,可以將 CPU 資源劃分為不同的組,以便更好地滿足不同應用場景的需求。
4.3進程狀態的轉換機制
進程在其生命周期內會經歷多種狀態的轉換,這些轉換受到資源分配的影響。例如,當一個進程從創建態轉變為就緒態時,它需要獲得除 CPU 以外的所有必要資源。一旦這些資源分配完成,進程就處于就緒狀態,等待 CPU 的分配。
當進程獲得 CPU 資源并開始執行時,它處于運行態。然而,在運行過程中,進程可能會因為等待某個事件(如等待 I/O 操作完成、等待資源分配等)而進入等待態。在等待態下,進程會被暫時掛起,以釋放 CPU 資源供其他進程使用。當等待的事件發生時,進程會被喚醒并重新進入就緒態。
此外,進程還可能因為時間片用完或被更高優先級的進程搶占 CPU 而從運行態回到就緒態。而當一個進程完成其任務或出現無法克服的錯誤時,它會進入終止態,等待操作系統進行善后處理。
學習編程就得循環漸進,扎實基礎,勿在浮沙筑高臺