父进程和子进程生命周期一般都不相同,父子进程程间互有长短。这就引出了下面两个问题
问题:谁是孤儿子进程的父进程?
- 进程ID为1的众进程之组------init会接管孤儿进程
- 换言之,某一子进程的父进程终止后,对getppid()的调用将返回1.这时判定某一子进程的"生父"是否"在世"的方法之一(前提是假设该子进程由 init 之外的进程创建)
注:使用参数 PR_SET_PDEATHSIG 调用 Linux 特有的系统调用 prctl(),将有可能导致某一进程在成为孤儿时收到特定信号。
问题:在父进程执行wait()之前,其子进程就已经终止,这将会发生什么?
- 此处的要点在于,即使子进程已经结束,系统仍然运行其父进程在以后的某一时刻去执行wait(),以确定该子进程是如何终止的。
- 内核通过将子进程转为僵尸进程(zombie)来处理这种情况。
- 这也意味着将释放子进程所把持的大部分资源,以便供其他进程重新使用
- 该进程所唯一保留的是内核检查表中的一条记录,其中包含了子进程ID、终止状态、资源使用数据等信息
至于僵尸进程名称的由来,则源于Unix系统对电影情节的效仿------无法通过信号来杀死僵尸进程,即使是SIGKILL。这就确保了父进程总是可以执行wait()方法
当父进程执行wait()之后,由于不再需要子进程搜索剩余的最后信息,故而内核将删除僵尸进程。另一方面,如果父进程未执行wait()随即退出,那么init进程将接管子进程并自动调用wait(),从而从系统中移除僵尸进程。
如果父进程创建了某一子进程,但并未执行 wait(),那么在内核的进程表中将为该子进程永久保留一条记录。如果存在大量此类僵尸进程,它们势必将填满内核进程表,从而阻碍新进程的创建。既然无法用信号杀死僵尸进程,那么从系统中将其移除的唯一方法就是杀掉它们的父进程(或者等待父进程终止),此时init进程将接管和等待这些僵尸进程,从而从系统中将它们清理调
在设计长生命周期的父进程(例如:会创建众多子进程的网络服务器和 Shell)时,这些语义具有重要意义。换句话说,在此类应用中,父进程应执行 wait()方法,以确保系统总是能够清理那些死去的子进程,避免使其成为长寿僵尸。父进程在处理 SIGCHLD 信号时,对 wait()的调用既可同步,也可异步
下面 展示了一个僵尸进程的创建,以及发送 SIGKILL 信号无法杀死僵尸进程的例子:
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <zconf.h>
#include <sys/wait.h>
#include <errno.h>
#define CMD_SIZE 200
int
main(int argc, char *argv[])
{
char cmd[CMD_SIZE];
pid_t childPid;
setbuf(stdout, NULL); /* Disable buffering of stdout */
printf("Parent PID=%ld\n", (long) getpid());
switch (childPid = fork()) {
case -1:
perror("fork");
exit(EXIT_FAILURE);
case 0: /* Child: immediately exits to become zombie */
printf("Child (PID=%ld) exiting\n", (long) getpid());
_exit(EXIT_SUCCESS);
default: /* Parent */
sleep(3); /* Give child a chance to start and exit */
snprintf(cmd, CMD_SIZE, "ps | grep %s", basename(argv[0]));
system(cmd); /* View zombie child */
/* Now send the "sure kill" signal to the zombie */
if (kill(childPid, SIGKILL) == -1){
perror("kill");
exit(EXIT_FAILURE);
}
sleep(3); /* Give child a chance to react to signal */
printf("After sending SIGKILL to zombie (PID=%ld):\n", (long) childPid);
system(cmd); /* View zombie child again */
exit(EXIT_SUCCESS);
}
}