功能說明:等待子行程中斷或結束。
標頭檔:#include <sys/wait.h> \n #include <sys/types.h>
函式宣告:pid_t waitpid(pid_t pid, int *status, int options);
函式說明:
1. waitpid()會暫停目前行程的執行,直到有訊號來到,或是子行程的結束。
2. 如果在呼叫waitpid()時子行程已經結束,則waitpid()會立即傳回子行程的結束狀態值。
3. 子行程的結束狀態值,會由第2個參數status以Call by Reference的方式傳回。
4. 若不在意子行程的結束狀態值,可將第2個參數status設定成NULL。
5. 第1個參數pid_t pid的設定如下:
a) pid < -1:等待行程群組識別碼為pid絕對值的任何子行程。
b) pid = -1:等待任何一個子行程,相當於wait()。
c) pid = 0:等待行程群組識別碼與目前行程相同的任何一個子行程。
d) pid > 1:等待任何子行程識別碼為pid的子行程。
這一部分我也搞不太懂何謂「行程的群組識別碼」??....@@
如果要把waitpid()當成wait()來用,就把pid設成-1;
至於第4種傳進子行程的PID,可以刻意地等待某個子行程的PID。但waitpid()的回傳值就是子行程的PID,那我們該如何事先得知?? 可以在子行程執行的過程中,將PID寫進暫存檔,如/var/run/*.pid_t,再從父行程去讀取。
6. 第3個參數int options的設定如下:
a) NULL:相當於wait()。
b) WNOHANG:如果沒有任何已經結束的子行程則馬上返回,不予等待。
c) WUNTRACED:如果子行程進入暫停執行情況則馬上返回,但結束狀態不予理會。
如果想把waitpid()當wait()用,就設成NULL值;WNOHANG (Wait_No_Hang)和WUNTRACED (Wait_Untraced)的定義如下:
/usr/include/bits/waitflags.h
// Bits in the third argument to "waitpid". #define WNOHANG 1 // Don't block waiting. #define WUNTRACED 2 // Report status of stopped children.設定成WNOHANG,是可以讓父行程不必等待子行程的回應而繼續做事 (寫的文謅謅的....~"~);
而WUNTRACED....「子行程進入"暫停執行"情況」,這一部分我也一直不知道該如何模擬....(先跳過)
回傳值:如果執行成功則傳回子行程識別碼 (CPID);如果有錯誤發生則傳回-1。
範例:
#include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <strings.h> #include <sys/wait.h> #include <signal.h> int main() { pid_t pid = -2, PPID = -3, CPID = -4; int nStatus = 0, _Exit = 0; pid = fork(); if (pid == 0) { signal(SIGHUP, SIG_DFL); CPID = getpid(); PPID = getppid(); printf("\nChild (PPID / CPID): %d / %d \n", PPID, CPID); usleep(10 * 1000000); exit(EXIT_SUCCESS); } PPID = getpid(); sleep(20); CPID = waitpid(-1, &nStatus, WNOHANG); printf("Parent (PPID / CPID): %d / %d \n", PPID, CPID); if (WIFEXITED(nStatus) != 0) { _Exit = WEXITSTATUS(nStatus); switch (_Exit) { default: printf("The Child Process EXIT-STATUS code: %d \n\n", _Exit); break; } } else if (WIFSIGNALED(nStatus) != 0) { _Exit = WTERMSIG(nStatus); switch (_Exit) { default: printf("The Child Process TERMINAL-SIGNAL code: %d \n\n", _Exit); break; } } /* else if (WIFSTOPPED(nStatus) != 0) { _Exit = WSTOPSIG(nStatus); switch (_Exit) { default: printf("The Child Process STOP-SIGNAL code: %d \n", _Exit); break; } } */ else printf("Child terminated abnormally. \n"); return 0; }首先,我各自在父子程序中均讀取父子行程的PID。在父行程中,讀取自己的PID,用getpid();讀取子行程的PID,則是用wait()或waitpid()。在子行程中,讀取自己的PID,也是用getpid();讀取父行程的PID,則用getppid()。
因為我要讓子行程比父行程先行結束,所以我在子行程的執行過程中睡眠10秒,而父行程則是20秒,好讓waitpid()接收子行程的執行結果狀態。
此外,為了印證WIFSIGNALED (Wait_If_Signaled)和WTERMSIG (Wait_Terminal_Signal)的功能,所以我在子行程的一開始就向系統註冊了一個SIGHUP (掛斷)的訊號。
執行結果:
直接執行主程式,而不做任何的動作,可以跟之前的wait()範例一樣,驗證WIFEXITED()和WEXITSTATUS()的功能;
執行主程式之後,我們開啟另一個終端機視窗,趕緊對子程序傳送一個掛斷 (HUP)的訊號 (因為子程序10秒后就會結束),輸入"kill -s SIGHUP (CPID)"。
然後等待父子程序結束,可以驗證WIFSIGNALED()和WTERMSIG()的用法,如下圖:
在上圖中,第一次的執行結果「The Child Process EXIT-STATUS code: 0」,0就是從子程序裡的"exit(EXIT_SUCCESS); "得來的;
第二次的執行結果「The Child Process TERMINAL-SIGNAL code: 1」,1就是訊號列表 (kill -l)中的1) SIGHUP。
在程式碼中,我還註解掉了一大段WIFSTOPPED() (Wait_If_Stopped)和WSTOPSIG() (Wait_Stop_Signal)的功能,因為我還搞不太清楚這一部份的用法。根據課本上的簡述,似乎是要搭配第3個參數WUNTRACED來使用。
沒有留言:
張貼留言