天天看點

linux中wait系統調用

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

wait的函數原型是:

#include <sys/types.h> /* 提供類型pid_t的定義 */

#include <sys/wait.h>

pid_t wait(int *status);

傳回值: 如果執行成功則傳回子程序識别碼(PID),如果有錯誤發生則傳回-1。失敗原因存于errno中。

程序一旦調用了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 <unistd.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <errno.h>
  7. int main()
  8. {
  9. pid_t pc, pr;
  10. pc = fork();
  11. if ( pc < 0 ) /* 如果出錯 */
  12. printf("create child prcocess error: %s/n", strerror(errno));
  13. exit(1);
  14. }
  15. else if ( pc == 0) /* 如果是子程序 */
  16. printf("I am child process with pid %d /n", getpid());
  17. sleep(3);/* 睡眠3秒鐘 */
  18. exit(0);
  19. else /* 如果是父程序 */
  20. printf("Now in parent process, pid = %d/n", getpid());
  21. printf("I am waiting child process to exit./n");
  22. pr = wait(NULL); /* 在這裡等待子程序結束 */
  23. if ( pr > 0 ) /*子程序正常傳回*/
  24. printf("I catched a child process with pid of %d/n", pr);
  25. else /*出錯*/
  26. printf("error: %s/n./n", strerror(errno));

編譯并運作:

$ 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行結果列印出來前有3秒鐘的等待時間,這就是我們設定的讓子程序睡 眠的時間,隻有子程序從睡眠中蘇醒過來,它才能正常退 出,也就才能被父程序捕捉到。其實這裡我們不管設定子程序睡眠的時間有多長,父程序都會一直等待下去,讀者如果有興趣的話,可以試着自己修改一下這個數 值,看看會出現怎樣的結果。

如果參數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. int status;
  3. if ( pc < 0) /* 如果出錯 */
  4. printf("error occured./n");
  5. else if ( pc == 0 ) /* 子程序 */
  6. printf("This is child process with pid of %d./n", getpid());
  7. exit(3); /* 子程序傳回3 */
  8. else /* 父程序 */
  9. pr = wait(&status);
  10. if ( WIFEXITED(status) )   /* 如果WIFEXITED傳回非零值 */
  11. printf("The child process %d exit normally./n", pr);
  12. printf("the return code is %d./n", WEXITSTATUS(status));
  13. else /* 如果WIFEXITED傳回零 */
  14. printf("The child process %d exit abnormally./n", pr);

編譯并運作:

$ gcc wait2.c -o wait2

$ ./wait2

This is child process with pid of 1538.

the child process 1538 exit normally.