僵屍線程


來源: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);
}
復制代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM