在 UNIX/Linux 系統程式設計中,進程結束後的狀態處理是核心知識點。孤兒進程與殭屍進程是兩種截然不同的異常狀態,理解其成因、區別與處理機制,是編寫健壯系統程式的基礎。
| 特性 | 孤兒進程 | 殭屍進程 |
|---|---|---|
| 成因 | 父進程先於子進程結束 | 子進程結束,父進程未調用 wait/waitpid 回收 |
| 狀態 | 正常運行,只是無父進程 | 已終止,但保留 PCB 在進程表中 |
| 收養機制 | init 進程 (PID 1) 收養,負責回收 | 無自動收養,需父進程顯式回收 |
| 危害 | 極小,正常現象 | 佔用 PID、進程表項,大量時導致無法建立新進程 |
| 清理責任 | init 進程自動處理 | 父進程必須調用 wait/waitpid |
父進程先退出,子進程睡眠 2 秒後檢查父進程 ID:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
pid_t pid;
if ((pid = fork()) == -1) { // 注意:原文漏寫括號,此處修正
perror("fork");
return 1;
} else if (pid == 0) { // 子進程
printf("pid=%d, ppid=%d\n", getpid(), getppid()); // 初始父進程
sleep(2); // 讓父進程先退出
printf("pid=%d, ppid=%d\n", getpid(), getppid()); // 被 init 收養後
} else { // 父進程
exit(0); // 立即退出
}
return 0;
}
pid=1091, ppid=1090 // 父進程 PID 1090
pid=1091, ppid=1 // 父進程變為 init (PID 1)
子進程 1091 原父進程 1090 退出後,被 init 進程 (PID 1) 收養,成為孤兒進程。init 會週期性調用 wait 清理已終止的孤兒進程,避免其變成殭屍。
pid_t fork():建立子進程,父進程回傳子 PID,子進程回傳 0,失敗回傳 -1pid_t getpid():取得當前進程 IDpid_t getppid():取得父進程 IDvoid exit(int status):終止進程pid_t wait(int *status) / waitpid(pid_t pid, int *status, int options):阻塞等待子進程結束並回收資源
RUNNING → exit() → ZOMBIE → wait() → 清理
↓
(父進程先結束)
↓
ORPHAN → init收養 → 正常運行 → exit() → ZOMBIE → init wait() → 清理
下篇將詳細講解殭屍進程的產生機制、危害演示、多種回收策略(同步阻塞、非阻塞輪詢、SIGCHLD 信號處理)及最佳實踐模式。