僵尸进程(zombie process)

来源:互联网 发布:js设置 类 样式 编辑:程序博客网 时间:2024/05/18 10:09
僵尸进程是如何产生的?
当进程调用fork()后,子进程运行完毕后,先行退出,父进程继续运行,这时候,操作系统维护着退出的子进程的信息,如cpu时间,内核时间,退出的状态等等,需要被他的父进程收集。此时,退出的子进程状态是僵尸状态,如果父进程有很多僵尸子进程的话,系统的性能可能会收到影响。这时候,父进程可以调用wait()或waitpid()函数来收集僵尸子进程,从而使僵尸进程消失。
如何避免僵尸进程的产生?
(1)      利用信号量。当一个子进程退出时,父进程会收到SIGCHLD信号,这个信号的默认处理方式是忽略。如果设置该信号的处理方式为SIG_IGN,当子进程退出时。将其状态丢掉,这样就不会产生僵尸进程了。
注意:
POSIX.1 并没有指定当SIGCHLD被忽略的行为,在4.4BSD和FreeBSD 5.2.1中,即使SIGCHLD被忽略,也会产生僵尸进程. Mac OS X 10.3, 则不会。对于SVR4而言, 如果signal()或者sigset()设置忽略SIGCHLD,则不会产生僵尸进程。Solaris 9和Linux 2.4.22与SVR4使用一样的策略。
如果我们使用sigaction(), 我们可以设置标志位SA_NOCLDWAIT为避免僵尸进程。FreeBSD 5.2.1, Linux 2.4.22, Mac OS X 10.3和Solaris 9都支持这个策略,为了可移植性,推荐这种策略。
(2)      Fork() twice。调用fork两次也可以避免僵尸进程的产生,apue上的例子:
        if ((pid = fork()) == 0) {
            /* first child */
            if ((pid = fork()) > 0)
                exit(0);/* 第二次fork的父进程,就是第一个子进程 */
            /*
             * 这里是第二个子进程,他的父进程已经是init进程了
             * 因为他本来的父进程已经exit(0)了(见上)
             */
            sleep(2);
            printf("second child, parent pid = %d/n", getppid());
            exit(0);
        }
        /* 等待第一个子进程退出,如果不等的话,还会有僵尸出现!*/
        if (waitpid(pid, NULL, 0) != pid)  
        err_sys("waitpid error");
         /* 继续父进程的工作 */
当父进程比子进程先行退出时,子进程将由init进程接管,init进程将负责回收其子进程(包括自己直接产生的和接管的)的状态。所以
以下的代码是不会产生僵尸的:
         if ((pid = fork()) > 0) {
                exit(0);
             * 这里是第二个子进程,他的父进程已经是init进程了
             * 因为他本来的父进程已经exit(0)了(见上)
             */
            }
         else {
            /* 做子进程的工作,由于父进程先行退出,它将被init进程接管 */
        }
 
原创粉丝点击