在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD/SIGCLD信号处理函数调用waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵死进程,无法正常结束,此时即使是root身份kill -9也不能杀死这类进程。补救办法是杀死僵尸进程的父进程(僵死进程的父进程必然存在),僵死进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵死进程。
产生僵死进程的程序:
#include<stdio.h> #include<stdlib.h> #include<signal.h> #include<unistd.h> int main() { int i,pid; if((pid=fork())==0)//creat child pid { exit(0);//child pid exits,sending SIGCLD to parent pid } else { for(i=0;i<10;i++) sleep(5); } }
程序编译执行后,子进程退出发送SIGCLD信号给父进程,而父进程没有处理此信号的动作,导致子进程无法正常结束。
执行程序zombie的同时,打开另一个终端执行ps aux会有如下的情况:
从结果中可以看出,此子进程状态为Z+,是僵死进程
如何避免僵死进程?途径有两种:1.父进程忽略SIGCLD信号;2.父进程捕捉SIGCLD信号,在信号处理函数中获取子进程退出状态。
第一种情况直接在原程序中添加signal(SIGCLD,SIG_IGN)即可;
下面讨论第二种情况,加入信号处理函数:
#include<stdio.h> #include<stdlib.h> #include<signal.h> #include<unistd.h> void handle_sigcld(int signo) { int pid,status; pid=waitpid(-1,&status,0);//-1表示等待任何子进程 printf("child process %d exit with %d\n",pid,status); } int main() { int i,pid; //signal(SIGCLD,SIG_IGN);//忽略SIGCLD信号 signal(SIGCLD,handle_sigcld); if((pid=fork())==0)//creat child pid { exit(0);//child pid exits,sending SIGCLD to parent pid } else { for(i=0;i<10;i++) sleep(5); } }程序安装信号处理函数handle_sigcld,当子进程结束时,触发信号处理函数,等待子进程结束。