• 僵尸线程


    来源:http://www.cnblogs.com/dongzhiquan/archive/2012/07/12/2588906.html

    在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等.但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等),直到父进程通过wait / waitpid来取时才释放,此时该进程便成为僵尸进程。


    1.什么是僵尸进程?
        UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,而父进程还没有结束,那么他将变成一个僵尸进程.
        如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程,因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,看有没有哪个进程是 刚刚结束的这个进程的子进程,如果是的话,就由Init来接管他,成为他的父进程,从而保证每个进程都会有一个父进程.而Init进程会自动wait其子 进程,因此被Init接管的所有进程都不会变成僵尸进程.

    2.子进程结束后为什么要进入僵尸状态?
        因为父进程可能要取得子进程的退出状态等信息。

    3.僵尸状态是每个子进程比经过的状态吗?
        是的。任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这 是每个 子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。
        如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。

    4.如何查看僵尸进程:
        $ ps -el
        其中,有标记为Z的进程就是僵尸进程
        S代表休眠状态;D代表不可中断的休眠状态;R代表运行状态;Z代表僵死状态;T代表停止或跟踪状态

    5.僵尸进程的避免
        1、父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起
        2. 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收
        3. 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号
        4. 还有一些技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收还要自己做。

    复制代码
    #include "apue.h"
    #include <sys/wait.h>
    
    int main(void)
    {
        pid_t pid;
        if ((pid = fork()) < 0)
        {
            err_sys("fork error");
        } 
        else if (pid == 0)
        { 
            /**//* first child */
            if ((pid = fork()) < 0)
                err_sys("fork error");
            else if (pid > 0)
                exit(0); 
            /**//* parent from second fork == first child */
            /**//*
            * We're the second child; our parent becomes init as soon
            * as our real parent calls exit() in the statement above.
            * Here's where we'd continue executing, knowing that when
            * we're done, init will reap our status.
            */
            sleep(2);
            printf("second child, parent pid = %d ", getppid());
            exit(0);
        }
    
        if (waitpid(pid, NULL, 0) != pid) /**//* wait for first child */
        err_sys("waitpid error");
    
        /**//*
        * We're the parent (the original process); we continue executing,
        * knowing that we're not the parent of the second child.
        */
        exit(0);
    }
    复制代码


    微信公众号: 猿人谷
    如果您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】
    如果您希望与我交流互动,欢迎关注微信公众号
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

  • 相关阅读:
    实验六
    派生类构造函数的理解
    实验五
    随机数
    面向行的输入(随时添加新的理解)
    实验四
    循序渐进VUE+Element 前端应用开发(21)--- 省市区县联动处理的组件使用(转载)
    循序渐进VUE+Element 前端应用开发(20)--- 使用组件封装简化界面代码(转载)
    循序渐进VUE+Element 前端应用开发(19)--- 后端查询接口和Vue前端的整合(转载)
    循序渐进VUE+Element 前端应用开发(18)--- 功能点管理及权限控制 (转载)
  • 原文地址:https://www.cnblogs.com/heyonggang/p/3030979.html
Copyright © 2020-2023  润新知