1 #include <sys/types.h>
2 #include <sys/wait.h>
3 pid_t wait(int *status)
進程一旦調用了wait,就當即阻塞本身,由wait自動分析是否當前進程的某個子進程已經 退出,若是讓它找到了這樣一個已經變成殭屍的子進程,wait就會收集這個子進程的信息,並把它完全銷燬後返回;若是沒有找到這樣一個子進程,wait就 會一直阻塞在這裏,直到有一個出現爲止。編程
參數status用來保存被收集進程退出時的一些狀態,它是一個指向int類型的指針。但若是咱們對這個子進程是如何死掉的絕不在乎,只想把這個殭屍進程消滅掉,(事實上絕大多數狀況下,咱們都會這樣想),咱們就能夠設定這個參數爲NULL,就象下面這樣ide
pid = wait(NULL); 函數
若是成功,wait會返回被收集的子進程的進程ID,若是調用進程沒有子進程,調用就會失敗,此時wait返回-1,同時errno被置爲ECHILD。spa
下面就讓咱們用一個例子來實戰應用一下wait調用:3d
1 #include <sys/types.h> 2 3 #include <sys/wait.h> 4 5 #include <unistd.h> 6 7 #include <stdlib.h> 8 9 main() 10 11 { 12 13 pid_t pc,pr; 14 15 pc=fork(); 16 17 if(pc<0) 18 19 printf("error ocurred!/n"); 20 21 else if(pc==0){ 22 23 printf("This is child process with pid of %d/n",getpid()); 24 25 sleep(10); 26 27 } 28 29 else{ 30 31 pr=wait(NULL); 32 33 printf("I catched a child process with pid of %d/n"),pr); 34 35 } 36 37 exit(0); 38 39 }
編譯並運行:指針
1 $ cc wait1.c -o wait1 2 3 $ ./wait1 4 5 This is child process with pid of 1508 6 7 I catched a child process with pid of 1508
能夠明顯注意到,在第2行結果打印出來前有10秒鐘的等待時間,這就是咱們設定的讓子進程睡 眠的時間,只有子進程從睡眠中甦醒過來,它才能正常退出,也就才能被父進程捕捉到。其實這裏咱們無論設定子進程睡眠的時間有多長,父進程都會一直等待下 去,讀者若是有興趣的話,能夠試着本身修改一下這個數值,看看會出現怎樣的結果。數status:調試
1,WIFEXITED(status)這個宏用來指出子進程是否爲正常退出的,若是是,它會返回一個非零值。code
2, WEXITSTATUS(status)當WIFEXITED返回非零值時,咱們能夠用這個宏來提取子進程的返回值,若是子進程調用exit(5)退 出,WEXITSTATUS(status)就會返回5;若是子進程調用exit(7),WEXITSTATUS(status)就會返回7。請注意,如 果進程不是正常退出的,也就是說,WIFEXITED返回0,這個值就毫無心義。orm
下面經過例子來實戰一下咱們剛剛學到的內容:blog
1 #include <sys/types.h> 2 3 #include <sys/wait.h> 4 5 #include <unistd.h> 6 7 main() 8 9 { 10 11 int status; 12 13 pid_t pc,pr; 14 15 pc=fork(); 16 17 if(pc<0) 18 19 printf("error ocurred!/n"); 20 21 else if(pc==0){ 22 23 printf("This is child process with pid of %d./n",getpid()); 24 25 exit(3); 26 27 } 28 29 else{ 30 31 pr=wait(&status); 32 33 if(WIFEXITED(status)){ 34 35 printf("the child process %d exit normally./n",pr); 36 37 printf("the return code is %d./n",WEXITSTATUS(status)); 38 39 }else 40 41 printf("the child process %d exit abnormally./n",pr); 42 43 } 44 45 }
編譯並運行:
1 $ cc wait2.c -o wait2 2 3 $ ./wait2 4 5 This is child process with pid of 1538. 6 7 the child process 1538 exit normally. 8 9 the return code is 3.
固然,處理進程退出狀態的宏並不止這兩個,但它們當中的絕大部分在平時的編程中不多用到,就也不在這裏浪費篇幅介紹了,有興趣的讀者能夠本身參閱Linuxman pages去了解它們的用法。
進程同步:
有時候,父進程要求子進程的運算結果進行下一步的運算,或者子進程的功能是爲父進程提供了下 一步執行的先決條件(如:子進程創建文件,而父進程寫入數據),此時父進程就必須在某一個位置停下來,等待子進程運行結束,而若是父進程不等待而直接執行 下去的話,能夠想見,會出現極大的混亂。這種狀況稱爲進程之間的同步,更準確地說,這是進程同步的一種特例。進程同步就是要協調好2個以上的進程,使之以 安排好地次序依次執行。解決進程同步問題有更通用的方法,咱們將在之後介紹,但對於咱們假設的這種狀況,則徹底能夠用wait系統調用簡單的予以解決。請 看下面這段程序:
1 #include <sys/types.h> 2 3 #include <sys/wait.h> 4 5 main() 6 7 { 8 9 pid_t pc, pr; 10 11 int status; 12 13 14 15 pc=fork(); 16 17 18 19 if(pc<0) 20 21 printf("Error occured on forking./n"); 22 23 else if(pc==0){ 24 25 26 27 exit(0); 28 29 }else{ 30 31 32 33 pr=wait(&status); 34 35 36 37 } 38 39 }
這段程序只是個例子,不能真正拿來執行,但它卻說明了一些問題,首先,當fork調用成功 後,父子進程各作各的事情,但當父進程的工做告一段落,須要用到子進程的結果時,它就停下來調用wait,一直等到子進程運行結束,而後利用子進程的結果 繼續執行,這樣就圓滿地解決了咱們提出的進程同步問題。
waitpid系統調用在Linux函數庫中的原型是:
1 #include <sys/types.h> 2 3 #include <sys/wait.h> 4 5 pid_t waitpid(pid_t pid,int *status,int options)
options提供了一些額外的選項來控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED兩個選項,這是兩個常數,能夠用"|"運算符把它們鏈接起來使用,好比:
ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);
若是咱們不想使用它們,也能夠把options設爲0,如:
ret=waitpid(-1,NULL,0);
而WUNTRACED參數,因爲涉及到一些跟蹤調試方面的知識,加之極少用到,這裏就很少費筆墨了,有興趣的讀者能夠自行查閱相關材料。
看到這裏,聰明的讀者可能已經看出端倪了--wait不就是通過包裝的waitpid嗎?沒錯,察看<內核源碼目錄>/include/unistd.h文件349-352行就會發現如下程序段:
1 static inline pid_t wait(int * wait_stat) 2 3 { 4 5 return waitpid(-1,wait_stat,0); 6 7 }
waitpid的返回值比wait稍微複雜一些,一共有3種狀況:
當pid所指示的子進程不存在,或此進程存在,但不是調用進程的子進程,waitpid就會出錯返回,這時errno被設置爲ECHILD;
1 #include <sys/types.h> 2 3 #include <sys/wait.h> 4 5 #include <unistd.h> 6 7 main() 8 9 { 10 11 pid_t pc, pr; 12 13 14 15 pc=fork(); 16 17 if(pc<0) 18 19 printf("Error occured on forking./n"); 20 21 else if(pc==0){ 22 23 sleep(10); 24 25 exit(0); 26 27 } 28 29 30 31 do{ 32 33 pr=waitpid(pc, NULL, WNOHANG); 34 35 if(pr==0){ 36 37 printf("No child exited/n"); 38 39 sleep(1); 40 41 } 42 43 }while(pr==0); 44 45 if(pr==pc) 46 47 printf("successfully get child %d/n", pr); 48 49 else 50 51 printf("some error occured/n"); 52 53 }
編譯並運行:
1 $ cc waitpid.c -o waitpid 2 3 $ ./waitpid 4 5 No child exited 6 7 No child exited 8 9 No child exited 10 11 No child exited 12 13 No child exited 14 15 No child exited 16 17 No child exited 18 19 No child exited 20 21 No child exited 22 23 No child exited 24 25 successfully get child 1526
父進程通過10次失敗的嘗試以後,終於收集到了退出的子進程。
由於這只是一個例子程序,不便寫得太複雜,因此咱們就讓父進程和子進程分別睡眠了10秒鐘和1秒鐘,表明它們分別做了10秒鐘和1秒鐘的工做。父子進程都有工做要作,父進程利用工做的簡短間歇察看子進程的是否退出,如退出就收集它。