waitpid()設置WNOHANG位(非阻塞模式)判斷子進程的狀態是否有所改變


參考《Linux/Unix系統編程手冊》26.1.5,對於系統調用waitid()

#include <sys/wait.h>

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

若在option中設置WNOHANG位,與那么該系統調用就是非阻塞的,也就是說會立刻返回而不是等待子進程的狀態發生變化。

如果子進程的狀態(正在運行or正常退出or被信號終止or被信號停止)發生變化,則會把狀態具體信息保存在類型為siginfo_t結構的變量中。

PS:在sigaction處理信號時,也可以選用這個結構。

書上特意強調了一種情況,那就是,對於這種非阻塞操作假如子進程狀態並未發生變化(也就是說正在運行,阻塞狀態也可以算作未發生變化),infop指向的結構信息不會發生任何變化,因此需要預先memset將infop指向的結構每一位置為0,如果調用waitid()之后仍為0,則代表子進程狀態未發生變化(簡單來講可理解為未退出)。

siginfo_t info;
// TODO:設置好waitid()的幾個參數idtype、id、options
// ...
memset(&info, 0, sizeof(siginfo_t));
if (waitid(idtype, id, &info, options | WNOHANG) == -1)
    // TODO: 錯誤處理
    exit(1);
if (info.si_pid == 0) {
    // 子進程狀態未發生改變
} else {
    // 子進程狀態發生改變,狀態信息存儲到了info中
}

然后我就想到了,如果是使用waitpid()呢?

#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);

waitpid()僅僅將狀態保存在int變量status中,書上很多代碼是像這樣

int status;
if (waitpid(pid, &status, options) == -1) {
    // TODO: 錯誤處理
    exit(1);
}

這有個問題,就是status並沒有進行初始化,以前寫C++的時候,記住的一條准則就是別忘記給變量賦初值。但是發現在很多C代碼中都沒有這個行為,之前在哪里看過這有利於檢查錯誤,因為往往未賦初值的變量會導致錯誤,於是一直就這么寫下來了。

於是我在寫了份測試代碼:調用fork()創建進程,子進程休眠1秒就_exit(1)退出,父進程則立刻調用waitpid(childPid, &status, WNOHANG);

理論上父進程的waitpid返回0(調用成功),因為childPid是對的,但是status狀態千奇百怪,后來發現原因就是:子進程狀態未發生改變時,status的值不變,於是status就是系統默認初始值(並未確定)。

按照waitid()的思路,就是給status一個初值,然后檢查調用waitpid()調用后status的值是否發生了變化。

問題就來了,status該設為什么值呢?

其實這里設為-1就行了。

那么有人會問,如果_exit(-1);退出呢?

退出碼是個1字節的整型,而int至少占2個字節,也就是初始狀態為11111111 11111111

而如果waitpid()得到的status為-1,其實是1個字節,轉換成2個字節int后就是11111111 00000000(小端模式下),和原來的-1有所不同。

實驗結果也證明了這點

第1個結果是子進程阻塞,status不變,因此狀態status為最初的-1,未知

第2個結果是父進程先阻塞再調用waitpid(),此時子進程已經_exit(-1)退出了,狀態status經過WEXITSTATUS轉換后是255,即(unsigned char)-1。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM