進程一章講過用wait和waitpid函數清理僵尸進程,父進程可以阻塞等待子進程結束,也可以非阻 塞地查詢是否有子進程結束等待清理(也就是輪詢的方式)。采用第一種方式,父進程阻塞了就不 能處理自己的工作了;采用第二種方式,父進程在處理自己的工作的同時還要記得時不時地輪詢一 下,程序實現復雜。
其實,子進程在終止時會給父進程發SIGCHLD信號,該信號的默認處理動作是忽略,父進程可以自 定義SIGCHLD信號的處理函數,這樣父進程只需專心處理自己的工作,不必關心子進程了,子進程 終止時會通知父進程,父進程在信號處理函數中調用wait清理子進程即可。
下面編寫一個程序完成以下功能進行測試:父進程fork出子進程,子進程調用exit(1)終止,父進程自定 義SIGCHLD信號的處理函數,在其中調用wait獲得子進程的退出狀態并打印。
代碼:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>void handler(int sig)
{pid_t id;while ((id = waitpid(-1, NULL, WNOHANG)) > 0) { printf("wait child success: %d\n", id);}printf("child is quit! %d\n", getpid());
}int main() {signal(SIGCHLD, handler);pid_t cid;if ((cid = fork()) == 0) { // childprintf("child : %d\n", getpid());sleep(3);exit(1);}while (1) { printf("father proc is doing some thing!\n");sleep(1);}
}
運行效果如下:
事實上,由于UNIX 的歷史原因,要想不產生僵尸進程還有另外一種辦法:父進程調 用sigaction將SIGCHLD的處理動作置為SIG_IGN,這樣fork出來的子進程在終止時會自動清理掉,不 會產生僵尸進程,也不會通知父進程。系統默認的忽略動作和用戶用sigaction函數自定義的忽略 通常是沒有區別的,但這是一個特例。此方法對于Linux可用,但不保證在其它UNIX系統上都可 用。請編寫程序驗證這樣做不會產生僵尸進程
?