zombie不占用內存也不占用CPU,表面上我們可以不用在乎它們的存在,然而事實上UNIX系統限制了某一時刻能同時存在的進程的最大數目。如果程序不及時清理系統中的zombie,最終會導致進程數過多,當再次需要產生新進程時就會出錯。
鑒於上邊的原因,我們需要在子進程調用exit後在父進成中調用wait或waipid
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int &statloc);
pid_t waitpid(pid_t pid,int *statloc, int options);
Both return:process ID if OK,-1 on error
它們被父進程調用以獲取子進程結束信息、清除zombie。當父進成調用這兩個函數時
a 阻塞(如果它的子進程還在運行)
b 立即返回子進程結束信息(如果一個子進程已經結束並等待父進程獲取信息)
c 返回錯誤(如果不存在子進程)
兩個函數的不同在於wait會令調用者阻塞直至某個子進程終止而waitpid則可以通過設置一個選項來設置為非阻塞,另外waitpid並不是等待第一個結束的進程而是等待參數中pid指定的進程。
兩個函數中的變量statloc是一個指向int型數據的指針。如果此變量不是NULL,則結束的進程的termination status會被保存在statiloc所指向的內存的區域;如果我們不關心termination status,則可以把statloc置為NULL。
傳統的實現中這兩個函數返回的整數中特定的比特位被賦予了特定的含義。POSIX.1指定了一些包含在頭文件<sys/wait.h> 宏來查看這些termination status
Macro Description
WIFEXITED(status) 如果status是由一個正常結束的進程產生的則值為真,此時我們可以繼續使用宏WEXITSTATUS(status)來獲取exit或_exit的參數
WIFSIGNALED(status) 如果status是由一個異常結束(接受到一個信號)的進程產生的則值為真,此時使用宏WTERMSIG(status)來獲取信號數。
WIFSTOPPED(status) 如果status是由一個接受到信號目前終止的進程產生的則值為真,此時可以繼續調用宏WSTOPSIG(status)來查看是哪個信號導致進程終止。
waitpid的option常量
WNOHANG waitpid將不阻塞如果指定的pid並未結束
WUNTRACED 如果子進程進入暫停執行情況則馬上返回,但結束狀態不予以理會。
waitpid中pid的含義依據其具體值而變
pid==-1 等待任何一個子進程,此時waitpid的作用與wait相同
pid >0 等待進程ID與pid值相同的子進程
pid==0 等待與調用者進程組ID相同的任意子進程
pid<-1 等待進程組ID與pid絕對值相等的任意子進程
waitpid提供了wait所沒有的三個特性:
1 waitpid使我們可以等待指定的進程
2 waitpid提供了一個無阻塞的wait
3 waitpid支持工作控制
具體可以查看APUE page202
===========================================================================
進程一旦調用了wait,就立即阻塞自己,由wait自動分析是否當前進程的某個子進程已經退出,如果讓它找到了這樣一個已經變成僵屍的子進程,wait 就會收集這個子進程的信息, 並把它徹底銷毀後返回;如果沒有找到這樣一個子進程,wait就會一直阻塞在這裡,直到有一個出現為止。
wait(等待子進程中斷或結束)
相關函數 waitpid,fork
表頭文件
#include<sys/types.h>
#include<sys/wait.h>
定義函數 pid_t wait (int * status);
函數說明
wait()會暫時停止目前進程的執行,直到有信號來到或子進程結束。如果在調用wait()時子進程已經結束,則wait()會立即返
回子進程結束狀態值。子進程的結束狀態值會由參數status 返回,而子進程的進程識別碼也會一快返回。如果不在意結束狀態值,則
參數status 可以設成NULL。子進程的結束狀態值請參考waitpid()。
返回值
如果執行成功則返回子進程識別碼(PID),如果有錯誤發生則返回-1。失敗原因存於errno 中。
附加說明
范例 一
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
pid_t pid;
int status,i;
if(fork()= =0){
printf(“This is the child process .pid =%d\n”,getpid());
exit(5);
}else{
sleep(1);
printf(“This is the parent process ,wait for child...\n”;
pid=wait(&status);
i=WEXITSTATUS(status);
printf(“child’s pid =%d .exit status=%d\n”,pid,i);
}
}
執行
This is the child process.pid=1501
This is the parent process .wait for child...
child’s pid =1501,exit status =5
范例 二
#include<iostream>
#include<unistd.h>
#include<sys/wait.h>
using namespace std;
int main(void)
{
pid_t pid;
pid =fork();
if (pid<0)
exit(0);
else if (pid == 0)
{
//如果是子進程 睡眠20秒
cout<<"children : "<<getpid()<<endl;
sleep(20);
}
else
{ cout<<"hello! i'm parent process!"<<endl;
//如果是父進程在這裡等待
pid_t pr = wait(NULL);
cout<<pr<<endl;
}
return 0;
}
waitpid(等待子進程中斷或結束)
相關函數 wait,fork
表頭文件
#include<sys/types.h>
#include<sys/wait.h>
定義函數 pid_t waitpid(pid_t pid,int * status,int options);
函數說明
waitpid()會暫時停止目前進程的執行,直到有信號來到或子進程結束。如果在調用waitpid()時子進程已經結束,則waitpid()會立即返回子進程結束狀態值。子進程的結束狀態值會由參數status 返回,而子進程的進程識別碼也會一快返回。如果不在意結束狀態值,則參數status 可以設成NULL。參數pid 為欲等待的子進程識別碼,其他數值意義如下:
pid<-1 等待進程組識別碼為pid 絕對值的任何子進程。
pid=-1 等待任何子進程,相當於wait()。
pid=0 等待進程組識別碼與目前進程相同的任何子進程。
pid>0 等待任何子進程識別碼為pid 的子進程。
參數option 可以為0 或下面的OR 組合:
WNOHANG 如果沒有任何已經結束的子進程則馬上返回,不予以等待。
WUNTRACED 如果子進程進入暫停執行情況則馬上返回,但結束狀態不予以理會。
子進程的結束狀態返回後存於status,底下有幾個宏可判別結束情況:
WIFEXITED(status)如果子進程正常結束則為非0 值。
WEXITSTATUS(status)取得子進程exit()返回的結束代碼,一般會先用WIFEXITED 來判斷是否正常結束才能使用此宏。
WIFSIGNALED(status)如果子進程是因為信號而結束則此宏值為真WTERMSIG(status) 取得子進程因信號而中止的信號代碼,一般會先用WIFSIGNALED 來判斷後才使用此宏。
WIFSTOPPED(status) 如果子進程處於暫停執行情況則此宏值為真。一般只有使用WUNTRACED 時才會有此情況。
WSTOPSIG(status) 取得引發子進程暫停的信號代碼,一般會先用WIFSTOPPED 來判斷後才使用此宏。
返回值
如果執行成功則返回子進程識別碼(PID),如果有錯誤發生則返回-1。失敗原因存於errno 中。