一、什么是僵尸进程
子进程退出时,父进程并未对其发出的SIGCHLD
信号进行适当处理,导致子进程停留在僵死状态等待其父进程为其收尸,这个状态下的子进程就是僵死进程。
僵尸进程将会占据系统资源,由于系统的进程ID是有限的,所以大量的僵尸进程会导致用户创建进程失败。
二、避免僵尸进程两种方式
方式1
父进程可以马上退出,使得子进程成为孤儿进程,由系统将子进程的ppid改为1(init进程
),并由init进程
来回收子进程的资源。
实现这一要求的技巧是fork
两次。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
pid_t pid;
if((pid = fork())<0){
printf("fork err\n");
exit(0);
}else if(pid == 0){
if((pid = fork())<0){
printf("fork err\n");
exit(0);
}else if(pid > 0){
//第一次fork的子进程退出,此时第二次fork的子进程还在活动(sleep),
//退出后第二次fork的子进程将成为孤儿进程
exit(0);
}
sleep(2);
printf("second child,parent pid = %d\n",getppid());
exit(0);
}
//父进程等待第一次fork的子进程退出,由于子进程调用了exit(0),所以可以很快回收子进程资源并退出
if(waitpid(pid,NULL,0)!= pid){
printf("waitpid error\n");
exit(0);
}
exit(0);
}
方式2
父进程声明一个信号处理函数,得到子进程的退出信号,然后在信号处理函数调用wait函数彻底结束子进程。
#include<signal.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
pid_t pid;
void handle_child(int sig)
{
//得到子进程的退出信号后调用wait函数释放子进程资源
if(waitpid(pid,NULL,0)!=pid){
printf("waitpid error\n");
exit(0);
}
printf("child exit\n");
exit(0);
}
int main()
{
(void) signal (SIGCHLD,handle_child);
if((pid = fork())<0){
printf("fork error\n");
exit(0);
}
if(pid == 0){
//子进程睡眠2秒后退出
sleep(2);
exit(0);
}
while(1)
{
sleep(1);
}
}