1. 概念
僵尸进程是由于子进程死了,但是父进程没管,导致子进程的task_struct不释放,内核栈也无法释放,造成资源浪费。进程状态为Z。
僵尸进程没有释放的资源有:
在Linux系统中,僵尸进程在内核中没有释放的资源主要有以下两个:
内存资源:当子进程结束时,它会释放自己占用的内存资源。但是,如果没有父进程来回收僵尸进程,那么这些进程的状态信息就会一直保存在内核中,占据了一定的内存空间。
文件描述符资源:在Linux系统中,每个进程都有自己的文件描述符表,用于管理该进程打开的文件。当子进程结束时,它的文件描述符表应该被关闭,但是如果没有父进程来回收僵尸进程,那么这些进程的文件描述符表就会一直存在于内核中,占据了一定的文件描述符资源。
2. 解决方案
用sigchild信号解决僵尸进程的产生,通知父进程回收。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
void sys_err(char *str)
{
perror(str);
exit(1);
}
void do_sig_child(int signo) //信号处理函数
{
int status;
pid_t pid;
while ((pid = waitpid(0, &status, WNOHANG)) > 0) {//判断子进程状态
if (WIFEXITED(status))
printf("child %d exit %d\n", pid, WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("child %d cancel signal %d\n", pid, WTERMSIG(status));
}
}
int main(void)
{
pid_t pid;
int i;
for (i = 0; i < 5; i++) { //子进程创建
if ((pid = fork()) == 0)
break;
else if (pid < 0) //容错处理
sys_err("fork");
}
if (pid == 0) { //子进程分支
int n = 1;
while (n--) {
printf("child ID %d\n", getpid());
}
exit(i+1);
}
else if (pid > 0) { //父进程分支
struct sigaction act;
act.sa_handler = do_sig_child;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD, &act, NULL);
while (1) {
printf("Parent ID %d\n", getpid());
sleep(2);
}
}
return 0;
}
do_sig_child信号处理函数中可以while循环来处理收到的子进程退出信息。由于信号是没有消息队列的,所以如果有信号叠加的话会丢子进程退出信息。