小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Linux中的僵尸進程

 幸福的樂土 2012-02-16

解釋一:[1,2]

Unix編程中所謂"僵尸進程"指什么,什么情況下會產(chǎn)生僵尸進程,如何殺掉僵尸進程:

fork()/execve()過程中,假設子進程結束時父進程仍存在,而父進程fork()之前既沒安裝SIGCHLD信號處理函數(shù)調用waitwaitpid()等待子進程結束,又沒有顯式忽略該信號,則子進程成為僵尸進程,無法正常結束,此時即使是root身份kill -9也不能殺死僵尸進程(僵死進程實際上是已死的進程,你當然不能殺死一個死人)

●在一個進程調用了exit之后,該進程并非馬上就消失掉,而是留下一個稱為僵尸進程(Zombie)的數(shù)據(jù)結構。在Linux進程的5種狀態(tài)中,僵尸進程是非常特殊的一種,它已經(jīng)放棄了幾乎所有內(nèi)存空間,沒有任何可執(zhí)行代碼,也不能被調度,僅僅在進程列表中保留一個位置,記載該進程的退出狀態(tài)等信息供其他進程收集(如供父進程),除此之外,僵尸進程不再占有任何內(nèi)存空間。從這點來看,僵尸進程雖然有一個很酷的名字,但它的影響力遠遠抵不上那些真正的僵尸兄弟,真正的僵尸總能令人感到恐怖,而僵尸進程卻除了留下一些供人憑吊的信息,對系統(tǒng)毫無作用。

●系統(tǒng)調用exit,它的作用是使進程退出,但也僅僅限于將一個正常的進程變成一個僵尸進程,并不能將其完全銷毀。僵尸進程雖然對其他進程幾乎沒有什么影響,不占用CPU時間,消耗的內(nèi)存也幾乎可以忽略不計,但有它在那里呆著,還是讓人覺得心里很不舒服。而且Linux系統(tǒng)中進程數(shù)目是有限制的,在一些特殊的情況下,如果存在太多的僵尸進程,也會影響到新進程的產(chǎn)生。

●如何清理僵尸進程:用wait()waitpid()系統(tǒng)調用可以清理僵尸進程,或者殺死僵尸進程的父進程(僵尸進程的父進程必然存在),僵尸進程成為"孤兒進程",過繼給1號進程init,init始終會負責清理僵尸進程。

下面這段比喻形容了進程的一生,也更容易看出僵尸進程所處的階段:

隨著一句fork,一個新進程呱呱落地,但它這時只是老進程的一個克隆。

然后隨著exec,新進程脫胎換骨,離家獨立,開始了為人民服務的職業(yè)生涯。

人有生老病死,進程也一樣,它可以是自然死亡,即運行到main函數(shù)的最后一個"}",從容地離我們而去;也可以是自殺,自殺有2種方式,一種是調用exit函數(shù),一種是在main函數(shù)內(nèi)使用return,無論哪一種方式,它都可以留下遺書,放在返回值里保留下;它還甚至能可被謀殺,被其它進程通過另外一些方式結束他的生命。

進程死掉以后,會留下一具僵尸,waitwaitpid充當了殮尸工,把僵尸推去火化,使其最終歸于無形。

這就是進程完整的一生。[1,2]

處理:

*顯式忽略SIGCHLD信號是指類似這樣的代碼:

signal( SIGCHLD, SIG_IGN );

*安裝SIGCHLD信號句柄是指類似這樣的代碼:

View Code
static void on_sigchld ( int signo ) 
...{
pid_t pid;
int status;
while ( ( pid = waitpid( -1, &status, WNOHANG ) ) > 0 )
...{
/*
演示用,不推薦在信號句柄中使用fprintf()
*/
fprintf( stderr,
"child <%u> terminated", ( unsigned int )pid );
}
return;
}
/**//* end of on_sigchld */
... ...
signal( SIGCHLD, on_sigchld );

當然,不建議使用signal(),應該使用sigaction()[1]

解釋二:[3]

僵尸進程中保存著很多對程序員和系統(tǒng)管理員非常重要的信息,首先,這個進程是怎么死亡的?是正常退出呢,還是出現(xiàn)了錯誤,還是被其它進程強迫退出的?其次,這個進程占用的總系統(tǒng)CPU時間和總用戶 CPU時間分別是多少?發(fā)生頁錯誤的數(shù)目和收到信號的數(shù)目。這些信息都被存儲在僵尸進程中,試想如果沒有僵尸進程,進程一退出,所有與之相關的信息都立刻歸于無形,而此時程序員或系統(tǒng)管理員需要用到,就只好干瞪眼了。

那么,我們?nèi)绾问占@些信息,并終結這些僵尸進程呢?就要靠waitpid調用和wait調用。這兩者的作用都是收集僵尸進程留下的信息,同時使這個進程徹底消失。

wait

pid_t wait(int *statloc)

1進程一旦調用了wait,就立即阻塞自己,由wait自動分析是否當前進程的某個子進程已經(jīng)退出,如果讓它找到了這樣一個已經(jīng)變成僵尸的子進程,wait就會收集這個子進程的信息,并把它徹底銷毀后返回;如果沒有找到這樣一個子進程,wait就會一直阻塞在這里,直到有一個出現(xiàn)為止。

參數(shù)statloc用來保存被收集進程退出時的一些狀態(tài),它是一個指向int類型的指針。但如果我們對這個子進程是如何死掉的毫不在意,只想把這個僵尸進程消滅掉,(事實上絕大多數(shù)情況下,我們都會這樣想),我們就可以設定這個參數(shù)為NULL,就象下面這樣:

pid = wait(NULL);

如果成功,wait會返回被收集的子進程的進程ID,如果調用進程沒有子進程,調用就會失敗,此時wait返回-1,同時errno被置為ECHILD。

參數(shù)statloc

如果參數(shù)statloc的值不是NULL,wait就會把子進程退出時的狀態(tài)取出并存入其中,這是一個整數(shù)值(int),指出了子進程是正常退出還是被非正常結束的(一個進程也可以被其他進程用信號結束),以及正常結束時的返回值,或被哪一個信號結束的等信息。由于這些信息被存放在一個整數(shù)的不同二進制位中,所以用常規(guī)的方法讀取會非常麻煩,人們就設計了一套專門的宏(macro)來完成這項工作,下面我們來學習一下其中最常用的兩個:

● WIFEXITED(status)

這個宏用來指出子進程是否為正常退出的,如果是,它會返回一個非零值。

(請注意,雖然名字一樣,這里的參數(shù)status并不同于wait唯一的參數(shù)--指向整數(shù)的指針statloc,而是那個指針所指向的整數(shù),切記不要搞混了。)

● WEXITSTATUS(status)

WIFEXITED返回非零值時,我們可以用這個宏來提取子進程的返回值,如果子進程調用exit(5)退出,WEXITSTATUS (status)就會返回5;如果子進程調用exit(7),WEXITSTATUS(status)就會返回7。請注意,如果進程不是正常退出的,也就是說,WIFEXITED返回0,這個值就毫無意義。

有興趣的讀者可以自己參閱Linux man pages去了解它們的用法。

2進程同步

有時候,父進程要求子進程的運算結果進行下一步的運算,或者子進程的功能是為父進程提供了下一步執(zhí)行的先決條件(如:子進程建立文件,而父進程寫入數(shù)據(jù)),此時父進程就必須在某一個位置停下來,等待子進程運行結束,而如果父進程不等待而直接執(zhí)行下去的話,可以想見,會出現(xiàn)極大的混亂。這種情況稱為進程之間的同步,更準確地說,這是進程同步的一種特例。進程同步就是要協(xié)調好2個以上的進程,使之以安排好地次序依次執(zhí)行。

#include
#include
main()
{
pid_t pc, pr;
int status;
pc
=fork();
if(pc<0)
printf(
"Error occured on forking.n");
else if(pc==0){
/* 子進程的工作 */
exit(
0);
}
else{
/* 父進程的工作 */
pr
=wait(&status);
/* 利用子進程的結果 */
}
}

waitpid

pid_t waitpid(pid_t pid,int *status,int options)

從本質上講,系統(tǒng)調用waitpidwait的作用是完全相同的,但waitpid多出了兩個可由用戶控制的參數(shù)pidoptions,從而為我們編程提供了另一種更靈活的方式。下面我們就來詳細介紹一下這兩個參數(shù):

● pid

從參數(shù)的名字pid和類型pid_t中就可以看出,這里需要的是一個進程ID。但當pid取不同的值時,在這里有不同的意義。

pid>0時,只等待進程ID等于pid的子進程,不管其它已經(jīng)有多少子進程運行結束退出了,只要指定的子進程還沒有結束,waitpid就會一直等下去。

pid=-1時,等待任何一個子進程退出,沒有任何限制,此時waitpidwait的作用一模一樣。

pid=0時,等待同一個進程組中的任何子進程,如果子進程已經(jīng)加入了別的進程組,waitpid不會對它做任何理睬。

pid<-1時,等待一個指定進程組中的任何子進程,這個進程組的ID等于pid的絕對值。

● options

options提供了一些額外的選項來控制waitpid,目前在Linux中只支持WNOHANGWUNTRACED兩個選項,這是兩個常數(shù),可以用"|"運算符把它們連接起來使用,比如:

ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);

如果我們不想使用它們,也可以把options設為0,如:

ret=waitpid(-1,NULL,0);

如果使用了WNOHANG參數(shù)調用waitpid,即使沒有子進程退出,它也會立即返回,不會像wait那樣永遠等下去。

WUNTRACED參數(shù),由于涉及到一些跟蹤調試方面的知識,加之極少用到,有興趣的讀者可以自行查閱相關材料。

可以看出,wait不就是經(jīng)過包裝的waitpid。察看<內(nèi)核源碼目錄>/include/unistd.h文件349-352行就會發(fā)現(xiàn)以下程序段:

static inline pid_t wait(int * wait_stat)

{

return waitpid(-1,wait_stat,0);

}

返回值和錯誤

waitpid的返回值比wait稍微復雜一些,一共有3種情況:

當正常返回的時候,waitpid返回收集到的子進程的進程ID

如果設置了選項WNOHANG,而調用中waitpid發(fā)現(xiàn)沒有已退出的子進程可收集,則返回0;

如果調用中出錯,則返回-1,這時errno會被設置成相應的值以指示錯誤所在;

pid所指示的子進程不存在,或此進程存在,但不是調用進程的子進程,waitpid就會出錯返回,這時errno被設置為ECHILD

#include
#include
#include
main()
{
pid_t pc, pr;
pc=fork();
if(pc<0) /* 如果fork出錯 */
printf(
"Error occured on forking.n");
else if(pc==0){ /* 如果是子進程 */
sleep(
10); /* 睡眠10秒 */
exit(
0);
}
/* 如果是父進程 */
do{
pr
=waitpid(pc, NULL, WNOHANG); /* 使用了WNOHANG參數(shù),waitpid不會在這里等待 */
if(pr==0){ /* 如果沒有收集到子進程 */
printf(
"No child exitedn");
sleep(
1);
}
}
while(pr==0); /* 沒有收集到子進程,就回去繼續(xù)嘗試 */
if(pr==pc)
printf(
"successfully get child %dn", pr);
else
printf(
"some error occuredn");
}

更詳細參見[3]。

Linux中的進程基本狀態(tài):

    1、執(zhí)行(R)狀態(tài):CPU正在執(zhí)行,即進程正在占用CPU。

    2、就緒(W)狀態(tài):進程已經(jīng)具備的執(zhí)行的一切條件,正在等待分配CPU的處理時間片。

3、停止(S)狀態(tài):進程不能使用CPU。

三個函數(shù):

fork();功能:創(chuàng)建一個新的進程。(fork()<0[出錯]、fork()==0[子進程]、fork()>0[父進程]

wait();功能:真正結束進程(收尸)。

exec();功能:執(zhí)行外部程序。[4]

參考:

[1] http://blog.csdn.net/dai_weitao/archive/2007/08/01/1721184.aspx

[2] http://blog.csdn.net/upcuiling/archive/2006/04/26/678498.aspx

[3] http://blog.csdn.net/xjtuse_mal/archive/2007/05/31/1632185.aspx(詳細)

[4] http://blog.csdn.net/stevexk/archive/2006/05/15/729215.aspx

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多