📜  僵尸进程及其预防

📅  最后修改于: 2021-05-26 01:14:46             🧑  作者: Mango

先决条件: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);
    }
}

输出 :

zombie1_1

现在,在终端中使用以下命令检查过程表

$ ps -eaf

僵尸1_2

此处[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);
    }
}

输出:

zom_final

这里没有任何[a.out]失效,即没有创建任何Zombie进程。

想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。