linux中wait系統調用

系統中的殭屍進程都要由wait系統調用來回收,下面就通過實戰看一看wait的具體用法:

wait的函數原型是:

#include <sys/types.h> /* 提供類型pid_t的定義 */
#include <sys/wait.h>
pid_t wait(int *status);

進程一旦調用了wait,就立即阻塞自己,由wait自動分析是否當前進程的某個子進程已經退出,如果讓它找到了這樣一個已經變成殭屍的子進程,wait就會收集這個子進程的信息,並把它徹底銷燬後返回;如果沒有找到這樣一個子進程,wait就會一直阻塞在這裏,直到有一個出現爲止。

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

pid = wait(NULL);

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

下面就讓我們用一個例子來實戰應用一下wait調用:

  1. /* wait1.c */
  2. #include <sys/types.h>
  3. #include <sys/wait.h>
  4. #include <unistd.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <errno.h>
  8. int main()
  9. {
  10.     pid_t pcpr;
  11.    
  12.     pc = fork();
  13.     if ( pc < 0 )  /* 如果出錯 */
  14.     {
  15.         printf("create child prcocess error: %s/n"strerror(errno));
  16.         exit(1);
  17.     }
  18.     else if ( pc == 0) /* 如果是子進程 */ 
  19.     {
  20.         printf("I am child process with pid %d /n"getpid());
  21.         sleep(3);/* 睡眠3秒鐘 */
  22.         exit(0);
  23.     }
  24.     else  /* 如果是父進程 */
  25.     {
  26.         printf("Now in parent process, pid = %d/n"getpid());
  27.         printf("I am waiting child process to exit./n");
  28.         pr = wait(NULL);  /* 在這裏等待子進程結束 */
  29.         if ( pr > 0 ) /*子進程正常返回*/
  30.             printf("I catched a child process with pid of %d/n"pr);
  31.         else /*出錯*/
  32.             printf("error: %s/n./n"strerror(errno));
  33.     }
  34.     exit(0);
  35. }

編譯並運行:

$ gcc wait1.c -o wait1
$ ./wait1
I am child process with pid 2351
Now in parent process, pid = 2350
I am waiting child process to exit.
I catched a child process with pid of 2351

可以明顯注意到,在第2行結果打印出來前有10秒鐘的等待時間,這就是我們設定的讓子進程睡眠的時間,只有子進程從睡眠中甦醒過來,它才能正常退出,也就才能被父進程捕捉到。其實這裏我們不管設定子進程睡眠的時間有多長,父進程都會一直等待下去,讀者如果有興趣的話,可以試着自己修改一下這個數值,看看會出現怎樣的結果。

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

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

(請注意,雖然名字一樣,這裏的參數status並不同於wait唯一的參數–指向整數的指針status,而是那個指針所指向的整數,切記不要搞混了。)

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

下面通過例子來實戰一下我們剛剛學到的內容:

  1. /* wait2.c */
  2. #include <sys/types.h>
  3. #include <sys/wait.h>
  4. #include <unistd.h>
  5. int main()
  6. {
  7.     int status;
  8.     pid_t pcpr;
  9.    
  10.     pc = fork();
  11.     if ( pc < 0) /* 如果出錯 */
  12.         printf("error occured./n");
  13.     else if ( pc == 0 ) /* 子進程 */
  14.     {
  15.         printf("This is child process with pid of %d./n"getpid());
  16.         exit(3)/* 子進程返回3 */
  17.     }
  18.     else  /* 父進程 */
  19.     {
  20.         pr = wait(&status);
  21.         if ( WIFEXITED(status) )   /* 如果WIFEXITED返回非零值 */
  22.         {
  23.             printf("The child process %d exit normally./n"pr);
  24.             printf("the return code is %d./n"WEXITSTATUS(status));
  25.         }
  26.         else  /* 如果WIFEXITED返回零 */
  27.             printf("The child process %d exit abnormally./n"pr);
  28.     }
  29.     exit(0);
  30. }

編譯並運行:

$ gcc wait2.c -o wait2
$ ./wait2
This is child process with pid of 1538.
the child process 1538 exit normally.
the return code is 3.

父進程準確捕捉到了子進程的返回值3,並把它打印了出來。

當然,處理進程退出狀態的宏並不止這兩個,但它們當中的絕大部分在平時的編程中很少用到,就也不在這裏浪費篇幅介紹了,有興趣的讀者可以自己參閱Linux man pages去了解它們的用法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章