wait() - Unix、Linux 系統呼叫
廣告
名稱
wait, waitpid - 等待程序狀態改變
語法
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t * infop , int options );
|
描述
所有這些系統呼叫都用於等待呼叫程序子程序的狀態更改,並獲取有關狀態已更改的子程序的資訊。狀態更改被認為是:子程序終止;子程序被訊號停止;或子程序被訊號恢復。對於終止的子程序,執行 wait 允許系統釋放與子程序關聯的資源;如果未執行 wait,則終止的子程序將保持“殭屍”狀態(請參見下面的註釋)。
如果子程序已經更改狀態,則這些呼叫會立即返回。否則,它們會阻塞,直到子程序更改狀態或訊號處理程式中斷呼叫(假設系統呼叫不會使用sigaction(2)的SA_RESTART標誌自動重新啟動)。在本頁的其餘部分,狀態已更改且尚未由這些系統呼叫之一等待的子程序被稱為可等待的。
wait() 和 waitpid()
wait() 系統呼叫掛起當前程序的執行,直到其一個子程序終止。呼叫wait(&status)等效於
waitpid() 系統呼叫掛起當前程序的執行,直到由pid引數指定的子程序更改狀態。預設情況下,waitpid() 僅等待終止的子程序,但此行為可以透過options引數修改,如下所述。
pid的值可以是
標籤 | 描述 |
< -1 | 表示等待任何程序組 ID 等於pid的絕對值的子程序。 |
-1 | 表示等待任何子程序。 |
0 | 表示等待任何程序組 ID 等於呼叫程序的程序組 ID 的子程序。 |
> 0 | 表示等待程序 ID 等於pid值的子程序。 |
options的值是以下常量中的一個或多個的 OR
|
標籤 | 描述 |
WNOHANG | 如果沒有任何子程序退出,則立即返回。 |
WUNTRACED | 如果子程序已停止(但未透過ptrace(2)跟蹤),則也返回。即使未指定此選項,也會提供已停止的跟蹤子程序的狀態。 |
WCONTINUED | (自 Linux 2.6.10 起)如果已停止的子程序已透過傳遞SIGCONT恢復,則也返回。 |
|
(對於僅限 Linux 的選項,請參見下文。)WUNTRACED和WCONTINUED選項僅在SIGCHLD訊號未設定SA_NOCLDSTOP標誌時有效(請參見sigaction(2))。
如果status不為 NULL,則wait() 和waitpid() 將狀態資訊儲存到它指向的int中。可以使用以下宏檢查此整數(這些宏採用整數本身作為引數,而不是指向它的指標,就像在wait() 和waitpid() 中一樣!)
標籤 | 描述 |
WIFEXITED(status) | 如果子程序正常終止,則返回 true,即透過呼叫exit(3)或_exit(2),或從 main() 返回。 |
WEXITSTATUS(status) | 返回子程序的退出狀態。這由子程序在呼叫exit() 或_exit() 中指定的status引數的最低有效 16-8 位或 main() 中 return 語句的引數組成。僅當WIFEXITED返回 true 時才應使用此宏。 |
WIFSIGNALED(status) | 如果子程序被訊號終止,則返回 true。 |
WTERMSIG(status) | 返回導致子程序終止的訊號編號。僅當WIFSIGNALED返回 true 時才應使用此宏。 |
WCOREDUMP(status) | 如果子程序產生了核心轉儲,則返回 true。僅當WIFSIGNALED返回 true 時才應使用此宏。此宏未在 POSIX.1-2001 中指定,並且在某些 Unix 實現(例如 AIX、SunOS)上不可用。僅在 #ifdef WCOREDUMP ... #endif 中使用此宏。 |
WIFSTOPPED(status) | 如果子程序被訊號傳遞停止,則返回 true;這僅在使用WUNTRACED或子程序正在被跟蹤(請參見ptrace(2))時才有可能。 |
WSTOPSIG(status) | 返回導致子程序停止的訊號編號。僅當WIFSTOPPED返回 true 時才應使用此宏。 |
WIFCONTINUED(status) | (自 Linux 2.6.10 起)如果子程序已透過傳遞SIGCONT恢復,則返回 true。 |
waitid()
waitid() 系統呼叫(自 Linux 2.6.9 起可用)提供了對要等待的子程序狀態更改的更精確控制。
idtype和id引數選擇要等待的子程序,如下所示
標籤 | 描述 |
idtype == P_PID | 等待程序 ID 與id匹配的子程序。 |
idtype == P_PGID | 等待任何程序組 ID 與id匹配的子程序。 |
idtype == P_ALL | 等待任何子程序;id被忽略。 |
要等待的子程序狀態更改透過在options中對以下標誌中的一個或多個進行 OR 來指定 |
WEXITED | 等待已終止的子程序。 |
WSTOPPED | 等待因訊號傳遞而停止的子程序。 |
WCONTINUED | 等待(先前已停止的)已透過傳遞SIGCONT恢復的子程序。 |
以下標誌還可以與options進行 OR |
WNOHANG | 與waitpid()相同。 |
WNOWAIT | 使子程序保持可等待狀態;以後的 wait 呼叫可以再次用於檢索子程序狀態資訊。 |
成功返回後,waitid() 將填充infop指向的siginfo_t結構的以下欄位 |
si_pid
| 子程序的程序 ID。 |
si_uid
| 子程序的真實使用者 ID。(此欄位在大多數其他實現中未設定。) |
si_signo
| 始終設定為SIGCHLD。 |
si_status
| 子程序的退出狀態,如傳遞給_exit(2)(或exit(3)),或導致子程序終止、停止或繼續的訊號。si_code欄位可用於確定如何解釋此欄位。 |
si_code
| 設定為以下之一:CLD_EXITED(子程序呼叫_exit(2));CLD_KILLED(子程序被訊號殺死);CLD_STOPPED(子程序被訊號停止);或CLD_CONTINUED(子程序被SIGCONT繼續)。 |
如果在options中指定了WNOHANG且沒有任何子程序處於可等待狀態,則waitid() 會立即返回 0,並且infop指向的siginfo_t結構的狀態未指定。為了區分這種情況與子程序處於可等待狀態的情況,在呼叫之前將si_pid欄位清零,並在呼叫返回後檢查此欄位中的非零值。
返回值
wait():成功時,返回已終止子程序的程序 ID;錯誤時,返回 -1。
waitpid():成功時,返回狀態已更改的子程序的程序 ID;錯誤時,返回 -1;如果指定了WNOHANG且pid指定的子程序尚未更改狀態,則返回 0。
waitid():成功時或如果指定了WNOHANG且id指定的子程序尚未更改狀態時返回 0;錯誤時,返回 -1。
在錯誤情況下,這些呼叫中的每一個都會將errno設定為適當的值。
錯誤
標籤 | 描述 |
ECHILD | (對於wait())呼叫程序沒有任何未等待的子程序。 |
ECHILD | (對於waitpid() 或waitid())由pid(waitpid())或idtype和id(waitid())指定的程序不存在或不是呼叫程序的子程序。(如果 SIGCHLD 的操作設定為 SIG_IGN,則這可能發生在自己的子程序上。另請參見有關執行緒的 LINUX 註釋部分。) |
EINTR |
未設定WNOHANG,並且捕獲了未阻塞的訊號或SIGCHLD。 |
EINVAL | options引數無效。 |
註釋
終止但尚未等待的子程序將變為“殭屍”。核心維護有關殭屍程序的最小資訊集(PID、終止狀態、資源使用資訊),以便父程序稍後執行 wait 以獲取有關子程序的資訊。
只要殭屍程序未透過 wait 從系統中刪除,它就會佔用核心程序表中的一個槽,如果此表填滿,則將無法建立更多程序。如果父程序終止,則其“殭屍”子程序(如果有)將由init(8) 採用,後者會自動執行 wait 以刪除殭屍程序。
POSIX.1-2001 指定如果SIGCHLD的操作設定為SIG_IGN或為SIGCHLD設定了SA_NOCLDWAIT標誌(請參見sigaction(2)),則終止的子程序不會變為殭屍,並且對wait() 或waitpid() 的呼叫將阻塞,直到所有子程序都終止,然後失敗,並將errno設定為ECHILD。(原始 POSIX 標準將SIGCHLD設定為SIG_IGN的行為留為未指定。)Linux 2.6 符合此規範。但是,Linux 2.4(及更早版本)不符合:如果在忽略SIGCHLD時進行wait() 或waitpid() 呼叫,則該呼叫的行為就像沒有忽略SIGCHLD一樣,也就是說,該呼叫會阻塞直到下一個子程序終止,然後返回該子程序的程序 ID 和狀態。
Linux 註釋
在 Linux 核心中,核心排程執行緒並非與程序不同的構造。相反,執行緒僅僅是使用 Linux 獨有的 **clone**(2) 系統呼叫建立的程序;其他例程,例如可移植的 **pthread_create**(3) 呼叫,都是使用 **clone**(2) 實現的。 在 Linux 2.4 之前,執行緒只是程序的一種特殊情況,因此一個執行緒無法等待另一個執行緒的子程序,即使後者屬於同一個執行緒組。但是,POSIX 規定了此功能,並且從 Linux 2.4 開始,執行緒可以(並且預設會)等待同一執行緒組中其他執行緒的子程序。
以下 Linux 特定的 *選項* 用於使用 **clone**(2) 建立的子程序;它們不能與 **waitid**() 一起使用。
標籤 | 描述 |
__WCLONE | 僅等待“克隆”子程序。如果省略,則僅等待“非克隆”子程序。(“克隆”子程序是指在終止時不向其父程序傳遞訊號或傳遞除 **SIGCHLD** 之外的訊號的子程序。)如果也指定了 **__WALL**,則忽略此選項。 |
__WALL | (自 Linux 2.4 起)等待所有子程序,無論型別(“克隆”或“非克隆”)。 |
__WNOTHREAD | (自 Linux 2.4 起)不等待同一執行緒組中其他執行緒的子程序。這是 Linux 2.4 之前的預設設定。 |
示例
以下程式演示了 **fork**(2) 和 **waitpid**(2) 的用法。該程式建立一個子程序。如果未向程式提供命令列引數,則子程序使用 **pause**(2) 暫停其執行,以允許使用者向子程序傳送訊號。否則,如果提供了命令列引數,則子程序立即退出,使用命令列上提供的整數作為退出狀態。父程序執行一個迴圈,使用 **waitpid**(2) 監視子程序,並使用上面描述的 W*() 宏來分析等待狀態值。
以下 shell 會話演示了程式的用法。
$ ./a.out &
Child PID is 32360
[1] 32359
$ kill -STOP 32360
stopped by signal 19
$ kill -CONT 32360
continued
$ kill -TERM 32360
killed by signal 15
[1]+ Done ./a.out
$
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); }
if (cpid == 0) { /* Code executed by child */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Wait for signals */
_exit(atoi(argv[1]));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) { perror("waitpid"); exit(EXIT_FAILURE); }
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}
|
符合標準
SVr4、4.3BSD、POSIX.1-2001。
另請參見
廣告
|