僵尸进程及其预防
原文地址:Zombie Processes and their Prevention
僵尸态:在UNIX中使用 fork()
系统调用创建进程时,将复制父进程的地址空间。如果父进程调用 wait()
系统调用,那么将暂停父进程的执行,直到子进程终止。在子进程终止时,会生成一个 “SIGCHLD”
信号,该信号会由内核传递给父进程。父进程在收到 “SIGCHLD”
后会从进程表中获得子进程的状态。即使子进程终止了,在进程表中也有一个对应于子进程的条目,该条目存储了状态。当父级收集状态时,该条目将被删除。因此,将从系统中删除子进程的所有痕迹。如果父进程决定不等待子进程终止而执行后续任务,则在子进程终止时,父进程不会读取退出状态。因此,即使在终止子进程之后,进程表中仍会保留一个条目。子进程的这种状态称为僵尸态。
// A C program to demonstrate working of |
输出:
现在,在终端中使用以下命令检查进程表
$ ps -eaf |
此处 [a.out] 失效的条目显示了僵尸进程。
为什么我们需要阻止僵尸进程产生?
每个系统只有一个进程表。进程表的大小是有限的。如果生成太多僵尸进程,则进程表将会满。也就是说,系统将无法生成任何新进程,然后系统将陷入停顿。因此,我们需要防止创建僵尸进程。
可以防止创建僵尸的不同方式
使用 wait()
系统调用
父进程在创建子进程之后调用 wait()
时,它将等待子进程完成,并获得子进程的退出状态。父进程被挂起(在等待队列中等待),直到子进程终止。必须理解,在此期间,父进程只是等待而已。
// A C program to demonstrate working of |
通过忽略 SIGCHLD 信号
子进程终止时,相应的 SIGCHLD
信号会传递给父进程,如果我们调用 signal(SIGCHLD,SIG_IGN)
,则系统会忽略 SIGCHLD
信号,并从进程表中删除子进程条目。因此,不会创建僵尸进程。但是,在这种情况下,父进程无法知道子进程的退出状态。
// A C program to demonstrate ignoring |
通过使用信号处理程序
父进程为 SIGCHLD
信号设置信号处理程序。信号处理程序在其中调用 wait()
系统调用。在这种情况下,当子进程终止时,SIGCHLD
将传递给父进程。收到 SIGCHLD
时,将激活相应的处理程序,该处理程序将依次调用 wait()
系统调用。因此,父进程几乎立即收集了退出状态,并且清除了进程表中的子进程条目。因此,不会创建僵尸进程。
// A C program to demonstrate handling of |
输出:
这里没有任何[a.out]失效,即没有创建任何僵尸进程。