zoukankan      html  css  js  c++  java
  • 孤儿进程和僵尸进程

    转:http://blog.sina.com.cn/s/blog_4c6d89b20100h2od.html

    一、定义:什么是孤儿进程和僵尸进程
    僵尸进程:一个子进程在其父进程还没有调用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! ");
    else if(pid == 0) {
    printf("Hi father! I'm a ZOMBIE ");
    exit(0);  //(1)
    }
    else {
    sleep(10);
    wait(NULL);  //(2)
    }
    }

    (1) 向父进程发送SIGCHILD信号
    (2) 父进程处理SIGCHILD信号

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

    子进程将成为孤儿进程
    ------------------------------------------------------
    #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! ");
    else if(pid == 0) {
    sleep(6);
    printf("I'm a orphan ");
    exit(0);
    }
    else {
    sleep(1);
    printf("Children Bye! ");
    }
    }

    # ./a.out
    Children Bye!
    # I'm a orphan
    (回车后将会进入#)
    #
    二、影响:
    僵尸进程会占用系统资源,如果很多,则会严重影响服务器的性能
    孤儿进程不会占用系统资源
    处理流程:
    只要父进程不等wait(sys/wait.h)子进程,子进程都将成为孤魂野鬼zombie(zombie),unix中默认父进程总是想看子进程死后的状态
    if  父进程比子进程先退出
    子进程将被init(id  =  1)收养,最后的结果是zombie子进程彻底再见,系统资源释放
    else
    {
    子进程的zombie将一直存在,系统资源占用...
    if  父进程dead
    子进程将被init(id  =  1)收养,最后的结果是zombie子进程彻底再见,系统资源释放
    else  类似的子进程zombie越来越多,系统就等死了!!!
    }
    三、如何防止僵尸进程
    首先明白如何产生僵尸进程:
    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 ", pid);
    return;
    }
    第二种方法:两次fork():转载
    在《Unix 环境高级编程》里关于这个在8.6节有非常清楚的说明。

    实例
    回忆一下8 . 5节中有关僵死进程的讨论。如果一个进程要fork一个子进程,但不要求它等待子进程终止,也不希望子进程处于僵死状态直到父进程终止,实现这一要求的诀窍是调用fork两次。程序8 - 5实现了这一点。在第二个子进程中调用sleep以保证在打印父进程ID时第一个子进程已终止。在fork之后,父、子进程都可继续执行——我们无法预知哪一个会先执行。如果不使第二个子进程睡眠,则
    在fork之后,它可能比其父进程先执行,于是它打印的父进程ID将是创建它的父进程,而不是init进程(进程ID1)。

    #include  <sys/types.h>
    #include  <sys/wait.h>
    #include  "ourhdr.h"

    int main(void)
    {
    pid_t  pid;

    if ( (pid = fork()) < 0)
    err_sys("fork error");
    else if (pid == 0) {
    if ( (pid = fork()) < 0)
    err_sys("fork error");
    else if (pid > 0)
    exit(0); 

    sleep(2);
    printf("second child, parent pid = %d ", getppid());
    exit(0);
    }

    if (waitpid(pid, NULL, 0) != pid)
    err_sys("waitpid error");

    exit(0);
    }
    //avoid zombie process by forking twice

  • 相关阅读:
    angular.js 头部默认值,不使用json提交数据
    D1-FFmpeg拼接视频
    B23-Carthage的使用
    B22-SVN在iOS开发的使用中遇到的问题
    C4-Cordova在iOS平台的使用
    C2-PhoneGap的环境搭建及iOS项目创建
    C0-PhoneGap之移动开发策略的选择(翻译)
    C1-PhoneGap和Cordova的关系和认识
    B21-iOS 开发的一些tips(下)
    B17-禅与 Objective-C 编程艺术的阅读笔记
  • 原文地址:https://www.cnblogs.com/cheng07045406/p/3345426.html
Copyright © 2011-2022 走看看