先决条件:C语言中的fork(),僵尸进程
僵尸状态:在UNIX中使用fork()系统调用创建进程时,将复制父进程的地址空间。如果父进程调用wait()系统调用,那么将暂停父进程的执行,直到子进程终止。在子进程终止时,会生成“ SIGCHLD”信号,该信号会由内核传递给父进程。家长在收到“ SIGCHLD”后会从过程表中获得孩子的状态。即使终止该子代,在过程表中也有一个与该子代相对应的条目,该条目存储了状态。当父级收集状态时,该条目将被删除。因此,将从系统中删除子进程的所有痕迹。如果父母决定不等待孩子的离职而执行其后续任务,则在孩子终止时,不读取退出状态。因此,即使在终止子进程之后,过程表中仍会保留一个条目。子进程的这种状态称为“僵尸”状态。
// A C program to demonstrate working of
// fork() and process table entries.
#include
#include
#include
#include
int main()
{
int i;
int pid = fork();
if (pid == 0)
{
for (i=0; i<20; i++)
printf("I am Child\n");
}
else
{
printf("I am Parent\n");
while(1);
}
}
输出 :
现在,在终端中使用以下命令检查过程表
$ ps -eaf
此处[a.out]失效的条目显示了僵尸进程。
为什么我们需要阻止创建僵尸进程?
每个系统只有一个过程表。过程表的大小是有限的。如果生成了太多的僵尸进程,则进程表将已满。也就是说,系统将无法生成任何新进程,然后系统将陷入停顿。因此,我们需要防止创建僵尸进程。
可以防止创建僵尸的不同方式
1.使用wait()系统调用:当父进程调用wait()时,在创建子进程后,它指示等待子进程完成,并获得子进程的退出状态。父进程被挂起(在等待队列中等待),直到子进程终止。必须理解,在此期间,父进程只是等待而已。
// A C program to demonstrate working of
// fork()/wait() and Zombie processes
#include
#include
#include
#include
int main()
{
int i;
int pid = fork();
if (pid==0)
{
for (i=0; i<20; i++)
printf("I am Child\n");
}
else
{
wait(NULL);
printf("I am Parent\n");
while(1);
}
}
2.通过忽略SIGCHLD信号:当子级终止时,相应的SIGCHLD信号会传递给父级,如果我们调用“ signal(SIGCHLD,SIG_IGN)”,则系统会忽略SIGCHLD信号,并且子级会被忽略流程条目将从流程表中删除。因此,不会创建僵尸。但是,在这种情况下,父母无法知道孩子的退出状态。
// A C program to demonstrate ignoring
// SIGCHLD signal to prevent Zombie processes
#include
#include
#include
#include
int main()
{
int i;
int pid = fork();
if (pid == 0)
for (i=0; i<20; i++)
printf("I am Child\n");
else
{
signal(SIGCHLD,SIG_IGN);
printf("I am Parent\n");
while(1);
}
}
3.通过使用信号处理程序:父进程为SIGCHLD信号安装信号处理程序。信号处理程序在其中调用wait()系统调用。在这种情况下,当子级终止时,SIGCHLD会传递给父级。收到SIGCHLD后,将激活相应的处理程序,该处理程序将依次调用wait()系统调用。因此,父级几乎立即收集了退出状态,并且清除了进程表中的子级条目。因此,不会创建僵尸。
// A C program to demonstrate handling of
// SIGCHLD signal to prevent Zombie processes.
#include
#include
#include
#include
void func(int signum)
{
wait(NULL);
}
int main()
{
int i;
int pid = fork();
if (pid == 0)
for (i=0; i<20; i++)
printf("I am Child\n");
else
{
signal(SIGCHLD, func);
printf("I am Parent\n");
while(1);
}
}
输出:
这里没有任何[a.out]失效,即没有创建任何Zombie进程。