Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux waitpid 非阻塞模式(WNOHANG)實戰詳解

編輯:Linux 教學

前言

waitpid() 是進程回收子進程狀態的核心系統調用。配合 WNOHANG 選項可實現非阻塞輪詢,避免父進程卡死在 wait() 上。本文結合實測代碼與輸出,逐幀解析三種典型返回值(-1、0、>0)的含義與應用場景。

一、函數原型與關鍵參數

pid_t waitpid(pid_t pid, int *status, int options);
參數說明
pid>0 等待特定 PID;-1 等待任意子進程;0 等待同組;<-1 等待組 ID
status輸出參數,配合 WIFEXITED/WEXITSTATUS 等宏解析
optionsWNOHANG 非阻塞;WUNTRACED 回收停止態;WCONTINUED 回收繼續態

二、三大返回值語義

返回值含義典型場景
-1出錯,errno 指示原因(ECHILD:無子進程)尚未 fork、或所有子進程已被回收
0非阻塞模式下:有子進程但均未退出子進程正在運行,父進程可繼續做其他事
>0成功回收,返回結束的子進程 PID子進程已退出,status 含退出碼/信號

三、實測代碼與輸出分析

#include 
#include 
#include 

int main() {
    pid_t pid;
    int status;

    // 1. 無子進程時調用
    pid = waitpid(-1, &status, WNOHANG);
    printf("1st waitpid: pid=%d, errno=%d\n", pid, errno);  // 輸出 -1, ECHILD

    // 2. fork 子進程,子進程睡眠 3 秒
    if ((pid = fork()) == 0) {
        sleep(3);
        _exit(42);
    }

    // 父進程立即非阻塞輪詢
    pid = waitpid(-1, &status, WNOHANG);
    printf("2nd waitpid: pid=%d\n", pid);  // 輸出 0(子進程未退出)

    // 父進程睡眠 4 秒後再試
    sleep(4);
    pid = waitpid(-1, &status, WNOHANG);
    printf("3rd waitpid: pid=%d, status=%d\n", pid, WEXITSTATUS(status)); // 輸出子進程 PID, 42

    return 0;
}

輸出解讀

1st waitpid: pid=-1, errno=10 (ECHILD)  // 無子進程
2nd waitpid: pid=0                      // 有子進程但未退出
3rd waitpid: pid=12345, status=42       // 成功回收

四、典型應用模式

1. 非阻塞輪詢 + 事件循環

while (1) {
    pid_t pid = waitpid(-1, &status, WNOHANG);
    if (pid > 0) handle_child_exit(pid, status);
    else if (pid == 0) {
        // 子進程仍在跑,處理網路/定時器等其他事件
        do_other_work();
    } else { // -1
        if (errno == ECHILD) break; // 沒孩子了
        perror("waitpid");
    }
}

2. 信號驅動回收(推薦)

void sigchld_handler(int sig) {
    int status;
    while (waitpid(-1, &status, WNOHANG) > 0) {
        // 循環回收所有已退出子進程
    }
}
signal(SIGCHLD, sigchld_handler); // 或 sigaction 設置 SA_RESTART|SA_NOCLDSTOP

優勢:無需輪詢,子進程退出即時通知,配合 WNOHANG 循環回收防止信號合併丟失。

五、常見坑點

  1. 忘記 WNOHANG:預設阻塞,父進程卡住無法處理其他事件。
  2. 未循環回收:信號處理函數中若只呼叫一次 waitpid,多子進程近乎同時退出時會漏回收(信號合併)。
  3. 忽略 ECHILD:無子進程時返回 -1,errno=ECHILD,非錯誤,應正常跳出循環。
  4. 殭屍進程:父進程從未 wait 導致子進程退出後長期佔用 task_struct(PID 洩漏)。

總結

waitpid(-1, &status, WNOHANG) 返回值三部曲:
-1 (ECHILD) → 沒孩子;
0 → 有孩子但還活著;
>0 → 孩子已歸西,拿走屍體(PID+狀態)。
生產環境首選 SIGCHLD + WNOHANG 循環回收,兼顧即時性與健壯性。

Copyright © Windows教程網 All Rights Reserved