程序控制之wait和waitpid函式

2022-05-04 20:15:26 字數 4519 閱讀 2829

當乙個程序正常或異常終止時,核心就向其父程序傳送sigchld訊號。因為子程序終止是個非同步事件(這可以在父程序執行的任何時候發生),所以這種訊號也是核心向父程序發的非同步通知。父程序可以選擇忽略該訊號,或者提供乙個該訊號發生時即被呼叫執行的函式(訊號處理程式)。對於這種訊號的系統預設動作是忽略它)。

呼叫wait或waitpid的程序可能會發生的情況:

如果程序由於接收到sigchld訊號而呼叫wait,則可期望wait會立即返回。但是如果在任意時刻呼叫wait,則程序可能會阻塞。

#include pid_t wait( 

int *statloc );

返回值:若成功則返回已終止子程序id,若出錯則返回-1

pid_t waitpid( pid_t pid,

int *statloc, int

options );

返回值:若成功則返回狀態改變的子程序id,若出錯則返回-1,若指定了wnohang選項且pid指定的子程序狀態沒有發生改變則返回0

這兩個函式的區別如下:

如果乙個子程序已經終止,並且是乙個僵死程序,則wait立即返回並取得該子程序的狀態,否則wait使其呼叫者阻塞直到乙個子程序終止。如果呼叫者阻塞而且它有多個子程序,則在其乙個子程序終止時,wait就立即返回。因為wait返回終止子程序的程序id,所以它總能了解是哪乙個子程序終止了。

這兩個函式的引數statloc是乙個整型指標。如果statloc不是乙個空指標,則終止程序的終止狀態就存放在它所指向的單元內。如果不關心終止狀態,則可將該引數指定為空指標。

依據傳統,這兩個函式返回的整型狀態字是由實現定義的。其中某些位表示退出狀態(正常返回),其他位則指示訊號編號(異常返回),有一位指示是否產生了乙個core檔案等。posix.1規定狀態用定義在中的各個巨集來檢視。有四個互斥的巨集可用來取得程序終止的原因,它們的名字都以wif開始。基於這四個巨集中哪乙個值為真,就可選用其他巨集(表8-1說明欄中下劃線標註的巨集)來取得終止狀態、訊號編號等。這四個互斥的巨集示於表8-1中。

表8-1 檢查wait和waitpid所返回的終止狀態的巨集

巨集

說明

wifexited(status)

若為正常終止子程序返回的狀態,則為真。對於這種情況可執行wexitstatus(status),取子程序傳送給exit、_exit或_exit引數的低8位

wifsignaled(status)

若為異常終止子程序返回的狀態,則為真(接到乙個不捕捉的訊號)。對於這種情況,可執行wtermsig(status),取使子程序終止的訊號編號。另外,有些實現定義巨集wcoredump(status),若已產生終止程序的core檔案,則它返回真

wifstopped(status)

若為當前暫停子程序的返回狀態,則為真。對於這種情況,可執行wstopsig(status),取使子程序暫停的訊號編號

wifcontinued(status)

若在作業控制暫停後已經繼續的子程序返回了狀態,則為真。(posix.1的xsi擴充套件;僅用於waitpid。)

程式清單8-3 列印exit狀態的說明

[root@localhost apue]# cat prog8-3

.c#include

"apue.h

"#include

void

pr_exit(

intstatus)

程式清單8-4 演示不同的exit值(呼叫prog8-3中的pr_exit函式)

[root@localhost apue]# cat prog8-4

.c#include

"apue.h

"#include

intmain(

void

)

執行該程式可得:

[root@localhost apue]# ./prog8-4

normal termination, exit status = 7

abnormal termination, signal number = 6

abnormal termination, signal number = 8

不幸的是,沒有一種可移植的方法將wtermsig得到的訊號編號對映為說明性的名字。我們必須檢視標頭檔案才能知道sigabrt的值是6,sigfpe的值是8.

正如前面所述,如果乙個程序有幾個子程序,那麼只要有乙個子程序終止,wait就返回。如果要等待乙個指定的程序終止(如果知道要等待程序的id),那麼該如何做呢?posix.1定義了waitpid函式以提供這種功能(以及其他一些功能)。

對於waitpid函式中pid引數的作用解釋如下:

pid == –1

等待任一子程序。就這一方面而言,waitpid與wait等效。

pid > 0

等待其程序id與pid相等的子程序。

pid == 0

等待其組id等於呼叫程序組id的任一子程序。

pid < –1

等待其組id等於pid絕對值的任一子程序。

waitpid函式返回終止子程序的程序id,並將該子程序的終止狀態存放在由status指向的儲存單元中。對於wait,其唯一的出錯是呼叫程序沒有子程序(函式呼叫被乙個訊號中斷時,也可能返回另一種出錯)。但是對於waitpid,如果指定的程序或程序組不存在,或者引數pid指定的程序不是呼叫程序的子程序則都將出錯。

options引數使我們能進一步控制waitpid的操作。此引數可以是0,或者是表8-2中常量按位「或」運算的結果。

表8-2 waitpid的options常量

常量

說明

wcontinued

若實現支援作業控制,那麼由pid指定的任一子程序在暫停後已經繼續,但其狀態尚未報告,則返回其狀態

wnohang

若由pid指定的子程序並不是立即可用的,則waitpid不阻塞,此時其返回值為0

wuntraced

若某實現支援作業控制,而由pid指定的任一子程序已處於暫停狀態,並且其狀態自暫停以來還未報告過,則返回其狀態。wifstopped巨集確定返回值是否對應於乙個暫停子程序

waitpid函式提供了wait函式沒有提供的三個功能:

(1)waitpid可等待乙個特定的程序,而wait則返回任一終止子程序的狀態。

(2)waitpid提供了乙個wait的非阻塞版本。有時使用者希望取得乙個子程序的狀態,但不想阻塞。

(3)waitpid支援作業控制(利用wuntraced和wcontinued選項)。

如果乙個程序fork乙個子程序,但不要等待子程序終止,也不希望子程序處於僵死狀態直到父程序終止,實現這一要求的技巧是呼叫fork兩次。

程式清單8-5 呼叫fork兩次以避免僵死程序

[root@localhost apue]# cat prog8-5

.c#include

"apue.h

"#include

intmain(

void

)

else

if (pid == 0) /*

first child

*/

if (waitpid(pid, null, 0) != pid) /*

wait for first child

*/err_sys(

"waitpid error");

/** we're the parent ( the original process ); we continue executing,

* knowing that we're not the parent of the second child.

*/exit(0);

}

第二個子程序呼叫sleep以保證在列印父程序id時第乙個子程序已終止。在fork之後,父、子程序都可繼續執行,並且我們無法預知哪乙個會先執行。在fork之後,如果不使第二個子程序休眠,那麼它可能比其父程序先執行,於是它列印的父程序id將是建立它的父程序,而不是init程序(程序id 1)。

執行結果:

[root@localhost apue]# ./prog8-5

[root@localhost apue]# second child, parent pid = 1

注意,當原先的程序(也就是exec本程式的程序)終止時,shell列印其提示符,這在第二個子程序列印其父程序id之前。

本篇博文內容摘自《unix環境高階程式設計》(第二版),僅作個人學習記錄所用。關於本書可參考:

程序控制之wait3和wait4函式

大多數unix系統實現提供了另外兩個函式wait3和wait4。它們提供的功能比posix.1函式wait waitpid和waitid所提供的功能要多乙個,這與附加引數rusage有關。該引數要求核心返回由終止程序及其所有子程序使用的資源彙總。include include include inc...

Linux程序控制(三)wait

5.wait系列函式 include pid t wait int statloc pid t waitpid pid t pid,int statloc,int options 若成功,返回程序id 若出錯,返回0或 1 程序呼叫wait waitpid 若所有子程序還在執行,wait waitp...

程序控制之exit和waitpid wait 函式

1.exit函式 我們知道,程序有五種正常終止 1 從main函式執行return語句,如同呼叫exit一樣。2 呼叫exit。此函式有iso c定義,其操作包括呼叫各中終止處理程式,然後關閉所有標準i o流等。因為iso c並不處理檔案描述符,多程序以及作業控制,所以這一定義對unix系統是不完整...