而僵尸进程就是指:一个进程执行了exit系统调用退出,而其父进程并没有为它收尸(调用wait或waitpid来获得它的结束状态)的进程。
任何一个子进程(init除外)在exit后并非马上就消失,而是留下一个称外僵尸进程的数据结构,等待父进程处理。这是每个子进程都必需经历的阶段。另外子进程退出的时候会向其父进程发送一个SIGCHLD信号。
(在一个进程终止或者停止时,将SIGCHLD信号发送给其父进程。按系统默认将忽略此信号。如果父进程希望被告知其子系统的这种状态,则应捕捉此信号。信号的捕捉函数中通常调用wait函数以取得进程ID和其终止状态。)
js.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <signal.h> int main(int arg, char *args[]) { pid_t pid=fork(); //注册信号,屏蔽SIGCHLD信号,子进程退出,将不会给父进程发送信号,因此也不会出现僵尸进程 // signal(SIGCHLD,SIG_IGN); if(pid==-1) { printf("fork() failed! error message:%s\n",strerror(errno)); perror("fork() failed!"); return -1; } if(pid>0) { printf("I am father!(pid=%d)\n",getpid()); } if(pid==0) { usleep(10); printf("i am child!(pid=%d)\n",getpid()); } printf("over!\n"); return 0; }
father进程先退出,child进程后退出,发送的SIGCHLD信号忽略了。
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> void wait4children(int signo) { int status; while(waitpid(-1, &status, WNOHANG) > 0); } int main() { int i; pid_t pid; signal(SIGCHLD, wait4children); for(i=0; i<100; i++) { pid = fork(); if(pid == 0) break; } if(pid>0) { printf("press Enter to exit..."); getchar(); } return 0; }
但是使用了 signal(SIGCHLD, SIG_IGN); 同时又用waitpid;就会出现NO child processes。
(在man文档的waitpid里面有讲,如果进程设置SIGCHLD信号的处理为SIG_IGN时,那么waitpid调用就会返回ECHILD。)
一个方法就是:
signal(SIGCHLD, SIG_DFL);恢复默认设置。
如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <signal.h> void sig_handle(int sig) { waitpid(-1, NULL, 0); printf("llm->%s(%d)\n", __FUNCTION__, __LINE__); } int main(int argc, char *argv[]) { int rtn = 0; int pid = 0; char *arg[] = {"date", NULL}; signal(SIGCHLD, sig_handle);//waitpid: No child processes signal(SIGCHLD, SIG_IGN);//waitpid: No child processes 注释:usleep(10*1000);一样出现 // signal(SIGCHLD, SIG_DFL);//ok while(1) { pid = fork(); if(!pid) { execvp("date", arg); exit(1); } //usleep(10*1000); rtn = waitpid(pid, NULL, 0); if(rtn < 0) perror("waitpid"); } return 0; }
文章来源: 僵尸进程