wait&waitpid
進(jìn)程結(jié)束,無論是否正常中止,內(nèi)核都會給它的父進(jìn)程發(fā)送一個SIGCHILD的通知。(雖然這個老爸一點(diǎn)都不計劃生育也不在乎孩子,但是孩子死了總得通知他一下吧)。顯然這個通知是異步的,某天老爸下班回家可能就在郵箱里看到它若干孩子的死亡證明了。父進(jìn)程是比較不負(fù)責(zé)任的,所以它可能隨手把這個死亡證明扔了(ignore it),或者如果他比較愛那個孩子的話,就給它辦個葬禮(signal handler)。吶,都說了這個老爸是不負(fù)責(zé)任的,所以default方式就是扔了。
作為一個進(jìn)程,它調(diào)用wait或者waitpid的話會
1.block。 如果它所有的子進(jìn)程都在運(yùn)行(這里是否應(yīng)該理解為這些子進(jìn)程沒有死掉)
2.帶著某個子進(jìn)程的中止?fàn)顟B(tài)立即返回。如果有一個子進(jìn)程已經(jīng)中止并等待它父進(jìn)程來存取它的中止?fàn)顟B(tài)。
3,如果它已經(jīng)沒有子進(jìn)程了,就以錯誤退出。
wait會使調(diào)用者block,直到它有某個子進(jìn)程中止為止。而waitpid的第三個參數(shù)可使調(diào)用者不中止。
1、下面部分來自:http:///blog/65
第八章進(jìn)程控制,其中講到了僵死進(jìn)程,它的定義是這樣的: 在 UNIX 術(shù)語中,一個已經(jīng)終止,但其父進(jìn)程尚未對其進(jìn)行善后處理(獲取終止進(jìn)程的有關(guān)信息,釋放它仍占 有 的資源)的進(jìn)程被稱為僵死進(jìn)程( zombie )。
我創(chuàng)建了一個子進(jìn)程來做這些事情,和父進(jìn)程并行運(yùn)行,從而不引起服務(wù)中斷。代碼類似于:
這樣子進(jìn)程調(diào)用 exit() 進(jìn)入終止?fàn)顟B(tài)后,父進(jìn)程沒有調(diào)用 wait() / waitpid() 函數(shù),也沒有顯式忽略 SIGCHLD 信號,進(jìn)程就會進(jìn)入僵死狀態(tài)。我在程序運(yùn)行一段時間后,使用命令
果然發(fā)現(xiàn)了很多僵死進(jìn)程。僵死進(jìn)程消耗很小的計算機(jī)資源,但是 Linux 系統(tǒng)對運(yùn)行的進(jìn)程數(shù)量有限制,如果產(chǎn)生過多的僵尸進(jìn)程占用了可用的進(jìn)程號,將會導(dǎo)致新的進(jìn)程無法生成。但程序如果使用 wait() / waitpod() 阻塞等待的話,已經(jīng)失去創(chuàng)建子進(jìn)程的意義。 解決辦法一:程序在進(jìn)入終止?fàn)顟B(tài)時會向父進(jìn)程發(fā)送 SIGCHLD 信號,在 linux 上,如果在程序開始運(yùn)行時顯式忽略該信號可以避免僵死進(jìn)程的產(chǎn)生,代碼如下:
這樣做并不是一個標(biāo)準(zhǔn)的做法,因為在某些 UNIX 操作系統(tǒng)上,忽略該信號并不能避免僵死進(jìn)程的產(chǎn)生。 解決辦法二:更好的做法是調(diào)用 signal() 函數(shù)接管 SIGCHLD 信號,父進(jìn)程收到此信號后,執(zhí)行 waitpid() 函數(shù)為子進(jìn)程收尸。代碼如下:
waitpid() 函數(shù)在指定 WNOHANG 參數(shù)時,并不會阻塞進(jìn)程運(yùn)行。此時 waitpid() 作用為獲得進(jìn)程的運(yùn)行信息,當(dāng)子進(jìn)程沒有結(jié)束時返回值為 0, 在已經(jīng)結(jié)束則返回值為子進(jìn)程 ID.
2、下面的部分是轉(zhuǎn)來的,源網(wǎng)址http://doc./53457.html
查看linux源代碼 unistd.h 我們會發(fā)現(xiàn),其實 wait 就是經(jīng)過包裝的 waitpid:
staticinlinepid_twait(int*wait_stat)
{
returnwaitpid(-1,wait_stat,0); }
waitpid的返回值比wait稍微復(fù)雜一些,一共有3種情況: 1. 當(dāng)正常返回的時候,waitpid返回收集到的子進(jìn)程的進(jìn)程ID;
2. 如果設(shè)置了選項WNOHANG,而調(diào)用中waitpid發(fā)現(xiàn)沒有已退出的子進(jìn)程可收集,則返回0;
3. 如果調(diào)用中出錯,則返回-1,這時errno會被設(shè)置成相應(yīng)的值以指示錯誤所在;
當(dāng)pid所指示的子進(jìn)程不存在,或此進(jìn)程存在,但不是調(diào)用進(jìn)程的子進(jìn)程,waitpid就會出錯返回,這時errno被設(shè)置為ECHILD;
下面看一個簡單的例子:
下載:waitpid.c
/* waitpid.c */
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdio.h>
int main()
{
pid_t pc,pr; pc=fork();
if (pc<0)/* fork錯誤*/
{
printf("fork error\n");
exit(1);
}
else if(pc==0)/*在子進(jìn)程中*/
{
sleep(10);
exit(0);
}
else
{
do {/* 使用了WNOHANG參數(shù),waitpid不會在這里等待 */
pr=waitpid(pc,NULL,WNOHANG);
if (pr==0)
{
printf("No child exit\n");
sleep(1);
}
}while (pr==0);
if (pr==pc)
printf("successfully get child %d\n",pr);
else
printf("wait child error\n");
}
return 0;
}
編譯并運(yùn)行: $ gcc -o waitpid waitpid.c
$ ./waitpid
No child exit
No child exit
No child exit
No child exit
No child exit
No child exit
No child exit
No child exit
No child exit
No child exit
successfully get child 4607
父進(jìn)程經(jīng)過10次失敗的嘗試之后,終于收集到了退出的子進(jìn)程。父進(jìn)程和子進(jìn)程分別睡眠了10秒鐘和1秒鐘,代表它們分別作了10秒鐘和1秒鐘的工作。父子進(jìn)程都有工作要做,父進(jìn)程利用工作的簡短間歇察看子進(jìn)程的是否退出,如退出就收集它。
|
|