等待子程序結束wait()和waitpid()
父子程序有時需要簡單的程序間同步,如父程序等待子程序的結束。
linux提供了以下兩個等待函式:wait(),waitpid().
需要包含標頭檔案:
#include <sys/types.h>
#include <sys/wait.h>
1) pid_t wait(int *status);
功能:等待任一子程序終止,如果子程序終止了,此函式會回收子程序的資源。
呼叫wait函式的程序會被掛起(阻塞),直到它的一個子程序退出或收到一個不能被忽視的訊號時才被喚醒。
若呼叫程序沒有子程序或它的子程序已經結束,該函式立即返回。
引數:函式返回時,引數status中包含子程序退出時的狀態資訊。
子程序的退出資訊在一個int中包含了多個欄位,用巨集定義可以取出其中的每個欄位。
返回值:如果執行成功則返回子程序的程序號。出錯返回-1,失敗原因存在errno中。
取出子程序的退出資訊:
>> WIFEXITED(status)
如果子程序是正常終止的,取出的欄位值非零。
>>WEXITSTATUS(status)
返回子程序的退出狀態,退出狀態儲存在status變數的8~16位。
在用此巨集前應先用巨集WIFEXITED判斷子程序是否正常退出,正常退出才可以使用此巨集。
fork3.c程式碼展示:
編譯和執行結果如下:#include <sys/wait.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> int main(){ pid_t pid; pid = fork(); if(pid < 0){ printf("fork error.\n"); return -1; }else if(pid == 0){ int i = 0; for(i = 0;i < 3;i++){ printf("this is child process.\n"); sleep(1); } _exit(1); }else{ int status = 0; wait(&status); //wait the end of child process if(WIFEXITED(status)){ printf("child process return %d\n",WEXITSTATUS(status)); } printf("this is father process.\n"); } return 0; }
2) pid_t waitpid(pid_t pid, int *status, int options);
功能:等待指定子程序終止,如果子程序終止了,此函式會回收子程序的資源。
返回值:如果執行成功則返回子程序ID。出錯返回-1,失敗原因存於errno中。
---- 從本質上講,系統呼叫waitpid和wait的作用是完全相同的,但waitpid多出了兩個可由使用者控制的引數pid和options,從而為我們程式設計提供了另一種更靈活的方式。
pid:當引數pid取不同的值時,有不同的意義:
1> pid>0時,只等待程序ID等於pid的子程序,不管其它已經有多少子程序執行結束退出了,只要指定的子程序還沒有結束,waitpid就會一直等下去。
2> pid=-1時,等待任何一個子程序退出,沒有任何限制,此時waitpid和wait的作用一模一樣。
3> pid=0時,等待和該程序在同一個程序組中的任何子程序,如果某個子程序已經加入了別的程序組,waitpid不會對它做任何理睬。
4> pid<-1時,等待一個指定程序組中的任何子程序,這個程序組的ID等於pid的絕對值。
options:目前在Linux中只支援WNOHANG和WUNTRACED兩個選項,可以用”|“運算子把它們連線起來使用,如:
ret = waitpid(-1,NULL,WNOHANG|WUNTRACED);
WNOHANG,表示即使沒有子程序退出,它也會立即返回,不會像wait那樣永遠等下去。
WUNTRACED,與跟蹤除錯有關,極少用到。
waitpid的返回值比wait稍微複雜一些,一共有3種情況:
>> 正常返回的時候,waitpid返回收集到的子程序的程序ID;
>> 如果設定了選項WNOHANG,而呼叫中waitpid發現沒有已退出的子程序可收集,則返回0;
>> 呼叫中出錯,則返回-1,這時errno會被設定成相應的值以指示錯誤所在。例如:當pid所指示的子程序不存在,或此程序存在,但不是呼叫程序的子程序,waitpid就會出錯返回,這時errno被設定為ECHILD。