文章目錄
- 引言:進程的生命與狀態:動與靜的交響曲
- 一、操作系統中的進程狀態概述
- 1.1 經典的進程狀態模型
- 1.2 進程狀態轉換圖
- 二、Linux操作系統中的進程狀態
- 2.1 Linux進程狀態的分類
- 2.2 各狀態的詳細解釋
- 2.3 Linux進程狀態表
- 2.4 使用ps查看進程狀態
- 三、進程狀態具體分析
- 🖋?運行 R
- 🖋?睡眠 S
- 🖋?休眠 D
- 🖋?暫停 T
- 🖋?死亡 X
- 🖋?僵尸 Z
- 📖孤兒進程
- 總結:進程狀態的舞蹈

引言:進程的生命與狀態:動與靜的交響曲
每一個進程都擁有自己的生命軌跡,它們在CPU的調度下,按照某種規律從一個狀態轉變到另一個狀態。這些狀態是進程在操作系統內存空間中的各種“存在形式”,是它們生命周期的不同表現,承載著操作系統對每個進程的管理與調度。
在Linux這個龐大而復雜的宇宙中,每個進程如同宇宙中的星辰,承載著數據流動與信息處理的重任。而它們的生命周期,卻不僅僅是簡單的“開始”與“結束”。在這無盡的天際,進程的狀態不斷變化,如同風中的細沙,或穩靜、或急躁、或急促、或安逸。今天,我們將一同探索,深入理解Linux操作系統中進程狀態的神秘面紗。
一、操作系統中的進程狀態概述
操作系統中的進程狀態是進程在生命周期中可能處于的不同狀態。這些狀態幫助操作系統識別進程的運行情況,并在不同狀態間進行合理的資源分配。
操作系統中的經典進程狀態包括
就緒
、運行
、阻塞
和終止
。
1.1 經典的進程狀態模型
典型的操作系統中,進程狀態可以分為以下幾種:
在這種經典模型中,進程會在不同狀態之間流轉。具體來說:
就緒 -> 運行:CPU調度器分配CPU給就緒狀態的進程。
運行 -> 阻塞:進程等待I/O或其他資源時進入阻塞狀態。
阻塞 -> 就緒:等待的條件滿足后,進程重新進入就緒隊列,等待CPU調度。
運行 -> 終止:進程執行完畢或異常終止,進入終止狀態。
1.2 進程狀態轉換圖
該圖展示了一個經典進程狀態的轉換流程。箭頭表示進程狀態轉換的可能路徑。
二、Linux操作系統中的進程狀態
Linux操作系統在經典的進程狀態基礎上進行了一系列擴展,允許內核更細粒度地控制進程,尤其是當系統資源緊張或多任務并發性很高時。Linux內核中的進程狀態可以使用ps命令或讀取/proc文件系統來查看進程的狀態信息。
2.1 Linux進程狀態的分類
在進程的task_struct結構體中,state字段用來表示進程的當前狀態。根據內核中的定義,不同狀態的進程會被掛載在不同的等待隊列上,以實現細粒度的調度與控制。
而在我們 Linux 中,新建
、就緒
、運行
都可以看作 運行 R
這一個狀態,所以比較清晰
2.2 各狀態的詳細解釋
-
TASK_RUNNING:進程正在運行或準備運行。它可以被調度器分配到CPU執行。TASK_RUNNING的進程始終是就緒隊列的一部分。
-
TASK_INTERRUPTIBLE:進程處于可中斷等待狀態,等待某一條件滿足。進程在此狀態下可以被信號喚醒。(關于信號的知識我們在后面會講)
-
TASK_UNINTERRUPTIBLE:進程處于不可中斷的等待狀態。這通常用于等待特定資源(例如設備I/O操作完成)。進程在此狀態下不會被信號打斷,即便外部發送信號也不會響應。
-
TASK_STOPPED:進程被暫停,通常是由于接收到SIGSTOP信號或調試器干預,等待繼續或恢復信號。
-
TASK_TRACED:進程被調試工具(如gdb)跟蹤和控制。此狀態下的進程會暫停,直到調試器進一步控制。
-
EXIT_DEAD:進程終止后進入清理階段,等待系統回收資源
-
EXIT_ZOMBIE:進程已結束,系統未回收其資源。僵尸進程會保留在系統中,直到其父進程調用wait()系統調用收集它的退出狀態。
-
TASK_DEAD:表示進程已徹底結束,系統已回收其所有資源。
2.3 Linux進程狀態表
2.4 使用ps查看進程狀態
在Linux系統中,可以通過ps命令查看進程的狀態:
ps -aux
ps命令會顯示每個進程的詳細信息,其中狀態列標記著每個進程的狀態。狀態的含義如下:
- R : 運行或就緒狀態
- S:可終止等待
- D: 不可終止等待
- Z: 僵尸進程,等待回收
- X:終止死亡進程
- T: 停止狀態
我們也可以通過ps命令查看某個指定的進程的信息:
ps axj | grep 進程名字
三、進程狀態具體分析
🖋?運行 R
首先來看看第一種狀態 R
以我們以往的認知來說,一個程序在運行就表示該 進程 處于 運行 狀態,那么事實真的如此嗎?
先來看看下面這段代碼:
#include<iostream>
using namespace std;#include<unistd.h>
#include<sys/types.h>int main()
{while(1){cout << "I'm a process, my PID is:" << getpid() << endl;sleep(1);}return 0;
}
當前makefile
文件為:
myProcess:test.cppg++ -o myProcess test.cpp.PHONY:catPI
catPI:ps ajx | head -1 && ps ajx | grep myProcess | grep -v grep .PHONY:clean
clean:rm -r myProcess
通過 make catPI
指令調用 Makefile 中提前設定好的指令,查看當前進程信息
可以看到當前的進程狀態為 睡眠 S+
注: + 表示當前進程在前臺運行中
進程 難道沒有運行嗎?
運行了,但我們 很難捕捉到 對于 CPU 來說,將這么簡單的一句話輸出到屏幕上是一件很小的事,可能幾毫秒就完成了 而其他大多數時間,進程
都在外設等待隊列中 排隊 當我們將打印語句和睡眠語句屏蔽后,進程 不用在等待隊列中 排隊, CPU 就一直在處理死循環,此時可以觀察到 運行R 狀態
🖋?睡眠 S
睡眠 S 的本質就是 進程阻塞
,表示此時進程因等待某種資源而暫停運行;
睡眠 S 又稱為可中斷休眠,當 進程 等待時間過長時,我們可以手動將其關閉,應用卡死后強制關閉也是這個道理
還有一種方式終止進程:kill
kill -9 PID
終止進程,當進程在后臺運行時(狀態不加 +),我們是無法通過 ctrl+c 終止的,但kill
指令可以終止
🖋?休眠 D
還存在一種特殊睡眠狀態 休眠 D
,休眠 又被稱為不可中斷休眠,顧名思義,休眠 D 狀態下的 進程 是無法終止的,kill 指令和 OS都無能為力,只能默默等待 進程阻塞 結束,拿到資源了,進程 才會停止 休眠 D 狀態
終止 休眠 D 進程的一個方法就是切斷電源,此時進程是結束了,但整個系統也結束了
🖋?暫停 T
我們還可以使 進程 進入 暫停 T
狀態
- kill -19 PID 暫停進程
- kill -18 PID 恢復進程
在輸入暫停指令后,進程進進入暫停狀態
我們可以通過 kill -18 PID 使 進程 恢復運行,恢復后的 進程 在后臺運行
可以看到,恢復后進程繼續執行,并且狀態由T變為S
注意: 進程 在后臺運行時,是無法通過 ctrl+c·
指令終止的,只能通過 kill -9 PID
終止
在 gdb 中調試代碼時,打斷點實際上就是 使 進程 在指定行暫停運行,此時 進程 處于 追蹤暫停狀態 t
🖋?死亡 X
當進程被終止后,就處于 死亡 X 狀態
死亡狀態是無法在任務列表中觀察到的,死亡 X 狀態只是一個返回狀態
🖋?僵尸 Z
與死亡狀態相對應的還有一個 僵尸 Z 狀態
- 通俗來說,僵尸狀態 是給 父進程 準備的
- 當 子進程 被終止后,會先維持一個 僵尸 狀態,方便 父進程 來讀取到 子進程 的- 退出結果,然后再將 子進程 回收
- 單純的在 bash 環境下終止 子進程,是觀察不到 僵尸狀態 的,因為 bash 會執行回收機制,將 僵尸 回收
- 我們可以利用 fork() 函數自己創建 父子進程 關系,觀察到這一現象
代碼示例如下:
#include<iostream>
using namespace std;#include<unistd.h>
#include<sys/types.h>int main()
{pid_t ret = fork();if(ret == 0){while(1){cout << "I'm son process, my PID: " << getpid() << " PPID: " << getppid() << endl;sleep(1);}}else if(ret > 0){while(1){cout << "I'm father process, my PID: " << getpid() << " PPID: " << getppid() << endl;sleep(1);}}else{while(1){cout << "Make son process fail!" << endl;sleep(1);}}return 0;
}
此時進程開始執行
此時父子進程都處于常規睡眠狀態
此時輸入指令 kill -9 PID
即kill -9 1007716
終止 子進程
再次查看進程狀態:
僵尸進程如果不被回收,會導致內存泄漏問題和標識符占用問題
📖孤兒進程
孤兒進程是一種特殊的進程狀態
- 通過程序創建 父子進程
- 通過指令終止 父進程,此時 子進程 會被
OS
領養 - 子進程 的 父進程 變為
1號進程
- 子進程 就變成了一個
孤兒進程
同樣執行上述代碼,起初都正常運行
現在我們消滅父進程,觀察其執行結果和運行狀態
可以看到子進程被1號進程領養
假設 子進程
不被 1號進程
領養
子進程
退出時就會無人回收,成為一只游離的僵尸僵尸進程
有 內存泄漏 的風險- 因此
子進程
會被OS
領養
總結:進程狀態的舞蹈
Linux操作系統中的進程狀態,不僅僅是抽象的計算機術語,它們是系統中每個進程生命周期的具體體現。正如一場精彩的舞蹈,每個進程都有自己的節奏和步伐,它們或快速躍動,或緩慢舞動,或瞬間消失,而每個轉變都與操作系統對資源的調度和管理息息相關。
通過理解進程狀態與狀態轉變的過程,我們能夠更好地把握Linux系統的脈搏,掌握進程管理與調度的奧秘。這不僅是操作系統中的技術問題,更是數字世界中的一場優雅的舞蹈。
本篇關于進程狀態的介紹就暫告段落啦,希望能對大家的學習產生幫助,歡迎各位佬前來支持斧正!!!