Board logo

标题: 孤儿进程和僵尸进程 [打印本页]

作者: yuyang911220    时间: 2017-1-25 19:18     标题: 孤儿进程和僵尸进程

一、定义:什么是孤儿进程和僵尸进程
僵尸进程:一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出。这个子进程就是僵尸进程。
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
僵尸进程将会导致资源浪费,而孤儿则不会。
子进程持续10秒钟的僵尸状态(EXIT_ZOMBIE)
------------------------------------------------------
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
main()
{
    pid_t pid;
    pid = fork();
    if(pid < 0)
        printf("error occurred!/n");
    else if(pid == 0) {
        printf("Hi father! I'm a ZOMBIE/n");
        exit(0);      //(1)
    }
    else {
        sleep(10);
        wait(NULL);   //(2)
    }
}
(1) 向父进程发送SIGCHILD信号
(2) 父进程处理SIGCHILD信号

执行exit(0)时根据其父进程的状态决定自己的状态:
    如果父进程已经退出(没有wait),则该子进程将会成为孤儿进程过继给init进程
    如果其父进程还没有退出,也没有wait(),那么该进程将向父进程发送SIGCHILD信号,进入僵尸状态等待父进程为其收尸。如果父进程一直没有执行wait(),那么该子进程将会持续处于僵尸状态,如果父进程到死也没有执行wait则在死后会将zombie进程过继给init进程,由init进程来处理zombie进程,最终还是会死掉。



子进程将成为孤儿进程
------------------------------------------------------
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
main()
{
    pid_t pid;
    pid = fork();
    if(pid < 0)
        printf("error occurred!/n");
    else if(pid == 0) {
        sleep(6);
        printf("I'm a orphan/n");
        exit(0);
    }
    else {
        sleep(1);
        printf("Children Bye!/n");
    }
}
# ./a.out
Children Bye!
# I'm a orphan
(回车后将会进入#)
#


二、有什么害处:
僵尸进程会占用系统资源,如果很多,则会严重影响服务器的性能
孤儿进程不会占用系统资源,最终是由init进程托管,由init进程来释放它。
处理流程:
只要老爹不等wait(sys/wait.h)儿子,儿子都将成为孤魂野鬼zombie(zombie),unix中默认老爹总是想看儿子死后的状态(以便报仇)  
  if   老爹比儿子先再见  
  儿子将被init(id   =   1)收养,最后的结果是zombie儿子彻底再见,系统资源释放  
  else   
      {  
        儿子的zombie将一直存在,系统资源占用...  
        if   老爹dead   
            儿子将被init(id   =   1)收养,最后的结果是zombie儿子彻底再见,系统资源释放  
   
      else   类似的儿子zombie越来越多,系统就等死了!!!  
    }  


signal(SIGCHLD, SIG_IGN); //忽略SIGCHLD信号,这常用于并发服务器的性能的一个技巧
                          //因为并发服务器常常fork很多子进程,子进程终结之后需要
                          //服务器进程去wait清理资源。如果将此信号的处理方式设为
                          //忽略,可让内核把僵尸子进程转交给init进程去处理,省去了
                          //大量僵尸进程占用系统资源。(Linux Only)

三、如何防止僵尸进程
首先明白如何产生僵尸进程:
1、子进程结束后向父进程发出SIGCHLD信号,父进程默认忽略了它
2、父进程没有调用wait()或waitpid()函数来等待子进程的结束
第一种方法:  捕捉SIGCHLD信号,并在信号处理函数里面调用wait函数
转贴Richard Steven的Unix Network Programming代码
int
main(int argc, char **argv)
{
                ...
        Signal(SIGCHLD, sig_chld);
                for(;
                }
                ...
}
void
sig_chld(int signo)
{
        pid_t        pid;
        int        stat;
        while ( (pid = waitpid(-1, &stat, WNOHANG)) >; 0)
                printf("child %d terminated/n", pid);
        return;
}




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0