我們知道當(dāng)一個父進程創(chuàng)建一個子進程時,會調(diào)用wait()和waitpid()函數(shù)清理僵?進程,?進程可以阻塞等待?進程結(jié)束,也可以?阻塞地查詢是否有?進程結(jié)束等待清理(也就是輪詢的?式)。采?第?種?式,?進程阻塞了就不 能處理??的?作了;采?第?種?式,?進程在處理??的?作的同時還要記得時不時地輪詢? 下,程序?qū)崿F(xiàn)復(fù)雜。

1.wait()和waitpid()

(1)wait 函數(shù):用來等待任何一個子進程退出,由父進程調(diào)用。

1 #include<sys/types.h>2 #include<sys/wait.h>3 pid_t  wait(int* status);

返回值:成功返回被等待子進程的pid,失敗返回-1。 status:輸出型參數(shù),拿回子進程的退出信息。如果參數(shù)status不為空,則進程終止?fàn)顟B(tài)被保存于其中。 wait方式:阻塞式等待,等待的子進程不退出時,父進程一直不退出。 目的:回收子進程,系統(tǒng)回收子進程的空間。

依據(jù)傳統(tǒng),返回的整形狀態(tài)字是由實現(xiàn)定義的,其中有些位表示退出狀態(tài)(正常返回),其他位表示信號編號(異常返回),有一位表示是否產(chǎn)生了一個core文件等。 終止?fàn)顟B(tài)是定義在 sys/wait.h中的各個宏,有四可互斥的宏可以用來取得進程終止的原因。

WIFEXITED:正常返回時為真,可以執(zhí)行宏函數(shù) WEXITSTATUS獲取子進程傳送給exit、_exit或_Exit的參數(shù)的低8位。 
WIFSIGNALED :異常返回時為真,可以執(zhí)行宏函數(shù)WTERMSIG取得子進程終止的信號編號,另外,對于一些實現(xiàn),定義有宏WCOREDUMP宏,若以經(jīng)昌盛終止進程的core文件,則為真。 
WIFSTOPPED :若為當(dāng)前暫停子進程的返回的狀態(tài),則為真,可執(zhí)行WSTOPSIG取得使子進程暫停的信號編號。 
WIFCONTINUED:若在作業(yè)控制暫停后已經(jīng)繼續(xù)的子進程返回了狀態(tài),則為真,僅用于waitpid。

(2)waitpid:

1 #include<sys/types.h>2 #include<sys/wait.h>3 pid_t waitpid(pid_t pid,int* status,int options);

1>參數(shù)

從參數(shù)的名字pid和類型pid_t中就可以看出,這里需要的是一個進程ID。但當(dāng)pid取不同的值時,在這里有不同的意義。 
pid>0時,只等待進程ID等于pid的子進程,不管其它已經(jīng)有多少子進程運行結(jié)束退出了,只要指定的子進程還沒有結(jié)束,waitpid就會一直等下去。 
pid=-1時,等待任何一個子進程退出,沒有任何限制,此時waitpid和wait的作用一模一樣。 
pid=0時,等待同一個進程組中的任何子進程,如果子進程已經(jīng)加入了別的進程組,waitpid不會對它做任何理睬。 
pid<-1時,等待一個指定進程組中的任何子進程,這個進程組的ID等于pid的絕對值。

status參數(shù)與wait()函數(shù)的基本相同。

options參數(shù) 當(dāng)options參數(shù)為0時,與wait功能相同,仍是阻塞式等待,不提供額外功能,如果為下列常量按位或則提供更多功能: 
WCONTINUED:若實現(xiàn)支持作業(yè)控制,那么由pid指定的任一子進程在暫停后已經(jīng)繼續(xù),但狀態(tài)尚未報告,則返回狀態(tài) 
WNOHANG:若由pid指定的子進程并不是立即可用的,則waitpid不阻塞,即此時以非阻塞方式(輪詢式訪問的必要條件)等待子進程,并且返回0。 
WUNTRACED:若實現(xiàn)支持作業(yè)控制,而pid指定的任一子進程已經(jīng)暫停,且其狀態(tài)尚未報告,則返回其狀態(tài)

2>返回值: 
當(dāng)正常返回的時候,waitpid返回收集到的子進程的進程ID; 
如果設(shè)置了選項WNOHANG,而調(diào)用中waitpid發(fā)現(xiàn)沒有已退出的子進程可收集,則返回0; 
如果調(diào)用中出錯,則返回-1,這時errno會被設(shè)置成相應(yīng)的值以指示錯誤所在; 
當(dāng)pid所指示的子進程不存在,或此進程存在,但不是調(diào)用進程的子進程,waitpid就會出錯返回,這時errno被設(shè)置為ECHILD;

3>waitpid提供了三個wait所沒有的功能: 
1. waitpid可等待一個特定的進程 
2. waitpid提供了一個wait的非阻塞版本 
3. waitpid支持作業(yè)控制

2.關(guān)于SIGCHLD信號

其實,?進程在終?時會給?進程發(fā)SIGCHLD信號,該信號的默認(rèn)處理動作是忽略,?進程可以? 定義SIGCHLD信號的處理函數(shù),這樣?進程只需專?處理??的?作,不必關(guān)??進程了,?進程 終?時會通知?進程,?進程在信號處理函數(shù)中調(diào)?wait清理?進程即可。
一般情況下父進程收到這個信號的默認(rèn)處理是忽略這個信號,即就是不做任何處理,但是我們可以通過系統(tǒng)調(diào)用API:signal()來進行自定義處理句柄,進行驗證,具體代碼如下:

(1)驗證子進程退出時會給父進程發(fā)送SIGCHLD信號

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計算培訓(xùn),高端軟件開發(fā)培訓(xùn),項目經(jīng)理培訓(xùn)

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計算培訓(xùn),高端軟件開發(fā)培訓(xùn),項目經(jīng)理培訓(xùn)

程序完成以下功能:?進程fork出?進程,?進程調(diào)?exit(1) 終?,?進程?定SIGCHLD信號的處理函數(shù),在其中調(diào)?wait獲得?進程的退出狀態(tài)并打印。

 用kill -l指令查看17號信號:大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計算培訓(xùn),高端軟件開發(fā)培訓(xùn),項目經(jīng)理培訓(xùn)

 3.子進程的異步等待方式

(1)異步回收僵尸進程: 
fork()之后,非阻塞(異步)等待子進程(回收僵尸)。 
fork()之后,子進程和父進程分叉執(zhí)行,僵尸進程的產(chǎn)生是因為父進程沒有給子進程“收尸”造成的,又可以根據(jù)危害程度分為下述兩類: 
總體來說:當(dāng)子進程結(jié)束之后,但父進程未結(jié)束之前,子進程將成為僵尸進程。 
1)當(dāng)子進程結(jié)束之后,但父進程未結(jié)束之前,子進程將成為僵尸進程,父進程結(jié)束后僵尸被init進程回收。 
2)如果子進程結(jié)束了,但是父進程始終沒有結(jié)束,那么這個僵尸將一直存在,而且隨著exec,僵尸越來越多。

(2)實現(xiàn)代碼

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計算培訓(xùn),高端軟件開發(fā)培訓(xùn),項目經(jīng)理培訓(xùn)

 1 #include<stdio.h> 
 2 #include<stdlib.h> 
 3 #include<signal.h> 
 4 #include<unistd.h> 
 5 #include<sys/types.h> 
 6 #include<sys/wait.h> 
 7 void catchSig(int sig) 
 8 { 
 9      printf("father is catching,child is quit\n"); 
10      //以非阻塞方式等待所有異常退出的子進程 
11      pid_t id; 
12      while((id = waitpid(-1,NULL,WNOHANG)) > 0) 
13      {    
14          printf("wait child success:%d\n",id); 
15     } 
16  }   
17  int main() 
18  {    
19       signal(SIGCHLD,catchSig); 
20       pid_t pid1 = fork(); 
21       if(pid1 == 0)//child1 
22       {    
23           printf("child1:my pid is %d\n",getpid()); 
24           exit(-1);//子進程1異常終止 
25       } 
26       pid_t pid2 = fork();//child2 
27       if(pid2 == 0) 
28       { 
29           printf("child2:my pid is %d\n",getpid()); 
30           exit(-1);//子進程2異常退出 
31       } 
32       pid_t pid3 = fork();//child3 
33       if(pid3 == 0) 
34       { 
35           printf("child3:my pid is %d\n",getpid());//子進程3正常運行  
36       } 
37       while(1) 
38       {39          printf("father is waiting...\n"); 
40          sleep(1); 
41       } 
42       return 0;

大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計算培訓(xùn),高端軟件開發(fā)培訓(xùn),項目經(jīng)理培訓(xùn)

運行結(jié)果:大數(shù)據(jù)培訓(xùn),云培訓(xùn),數(shù)據(jù)挖掘培訓(xùn),云計算培訓(xùn),高端軟件開發(fā)培訓(xùn),項目經(jīng)理培訓(xùn)

 

http://www.cnblogs.com/33debug/p/7017215.html