進程生命周期
Linux是多任務操作系統,系統中的每個進程能夠分時復用CPU時間片,通過有效的進程調度策略實現多任務并行執行。進程在被CPU調度運行,等待CPU資源分配以及等待外部事件時會處于不同的狀態。進程狀態如下:
- 創建狀態:創建新進程;
- 就緒狀態:進程獲取可以運作所有資源及準備相關條件;
- 執行狀態:進程正在CPU中執行操作;
- 阻塞狀態:進程因等待某些資源而被跳出CPU;
- 終止狀態:進程消亡;
[新建] → [就緒] ? [運行] → [終止]↑ ↓└── [阻塞] ←─┘
linux內核中進程狀態
內核進程狀態定義如下。
/* Used in tsk->state: */
#define TASK_RUNNING 0x0000 // 運行或就緒
#define TASK_INTERRUPTIBLE 0x0001 // 可中斷睡眠,也叫輕度睡眠,可被信號或資源就緒喚醒
#define TASK_UNINTERRUPTIBLE 0x0002 // 深度睡眠,僅由資源就緒喚醒(不可被信號中斷)
#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) // 0x0102,中度睡眠,能被kill信號打斷
#define __TASK_STOPPED 0x0004
#define __TASK_TRACED 0x0008
/* Used in tsk->exit_state: */
#define EXIT_DEAD 0x0010 // 進程完全終止(資源已回收)
#define EXIT_ZOMBIE 0x0020 // 進程已終止,但父進程未回收其資源(wait() 未調用)
#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
進程狀態查詢方法
**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">ps</font>**
/**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">top</font>**
**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">cat /proc/<PID>/status</font>**
<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">ps</font>
/<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">top</font>
顯示的進程狀態
符號 | **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">ps</font>** /**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">top</font>** 狀態 | 對應內核狀態 | 場景描述 |
---|---|---|---|
R | Running | **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">TASK_RUNNING</font>** | 進程正在運行或就緒(等待CPU調度)。 |
S | Sleeping | **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">TASK_INTERRUPTIBLE</font>** | 可中斷睡眠 |
D | Uninterruptible | **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">TASK_UNINTERRUPTIBLE</font>** | 不可中斷睡眠 |
T | Stopped | **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">__TASK_STOPPED</font>** | 進程被暫停(如收到**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">SIGSTOP</font>** 、**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">SIGTSTP</font>** 信號)。 |
t | Traced | **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">__TASK_TRACED</font>** | 進程被調試器(如gdb)追蹤(通常在斷點處暫停)。 |
Z | Zombie | **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">EXIT_ZOMBIE</font>** | 僵尸進程(已終止但父進程未回收資源)。 |
X | Dead | **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">EXIT_DEAD</font>** (極少在 **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">ps</font>** 中看到) | 進程完全終止(資源已回收,通常瞬間狀態)。 |
I | Idle | (內核線程的特殊標記) | 內核空閑線程。 |
僵尸進程
進程已終止執行,但其父進程尚未調用 **wait()**
系統調用來回收它的資源(主要是退出狀態信息)。 這樣的進程稱為僵尸進程。
進程狀態為 Z
(Zombie)。
進程已經執行完成,但是沒有釋放pid,task_struct等資源。
系統pid資源是有限的,大量僵尸進程會耗盡系統pid。
下面是僵尸進程測試代碼。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {pid_t pid = fork();if (pid == 0) {printf("子進程退出\n");exit(0); // 子進程終止} else {sleep(60); // 父進程沒有調用 wait()}return 0;
}
結果如下。
root@VM:~$ ps aux | grep zom
root 10106 0.0 0.0 2364 576 pts/4 S+ 17:20 0:00 ./zombie_process_test
root 10107 0.0 0.0 0 0 pts/4 Z+ 17:20 0:00 [zombie_process_] <defunct>
孤兒進程
進程的父進程已經提前退出,而該進程仍然在運行。 這種進程稱為孤兒進程。
孤兒進程執行完后會被init進程回收。一般不會產生危害。
下面是孤兒進城的測試代碼。
#include <stdio.h>
#include <unistd.h>int main() {pid_t pid = fork();if (pid == 0) {sleep(60); // 子進程繼續運行printf("我是子進程,父進程已經退出\n");} else {printf("父進程退出\n");exit(0); // 父進程終止}return 0;
}
參考資料
- Professional Linux Kernel Architecture,Wolfgang Mauerer
- Linux內核深度解析,余華兵
- Linux設備驅動開發詳解,宋寶華
- linux kernel 4.12