wait函數

#include <sys/types.h>

#include <sys/wait.h>

?

pid_t wait(int *status);

?

僵尸進程。進程結束后放棄了幾乎所有的內存空間,沒有任何可以執行的代碼,也不能被調度,僅僅在進程列表中保留著一個位置,記載著該進程的退出狀態等信息供其他進程收集,除此之外僵尸進程不再占有任何內存空間。

當進程終止時,操作系統的隱式回收機制會:1.關閉所有文件描述符 2. 釋放用戶空間分配的內存。內核的PCB仍存在。其中保存該進程的退出狀態,此時是一個僵尸進程。(正常終止→退出值;異常終止→終止信號)

一個進程在終止時會關閉所有文件描述符,釋放在用戶空間分配的內存,但它的PCB還保留著,內核在其中保存了一些信息:如果是正常終止則保存著退出狀態,如果是異常終止則保存著導致該進程終止的信號是哪個。這個進程的父進程可以調用wait或waitpid獲取這些信息,然后徹底清除掉這個進程。

在shell終端執行的命令和程序,都是shell通過fork產生的子進程來完成的,因此在命令和程序結束后,shell終端進程也可以獲取子進程的結束狀態,通過特殊命令$?查看,如果為0,表示正常結束,如果為非0值,表示出現了錯誤。Shell調用wait或waitpid得到它的退出狀態同時徹底清除掉這個進程。

父進程調用wait函數可以回收子進程終止信息。該函數有三個功能:1.阻塞等待子進程退出(父進程調用該函數后,如果子進程沒死,則父進程阻塞并等待子進程結束);2. 獲取子進程結束狀態(退出原因);3.回收子進程殘留資源 (回收子進程結束后殘留在內核中的PCB資源),然后徹底清除掉這個進程。

進程的一生。隨著fork的成功執行,一個新的子進程產生,但此時它還只是父進程的克隆。然后隨著exec函數族,新進程脫胎換骨,開始獨立執行一個全新的程序,并完全替代了原有的父進程。進程結束,可以是自殺,也可以是他殺。自殺:遇到main函數的最后一個“}”、在main函數中使用return或者調用exit_exit;他殺:被其它進程通過另外一種方式殺掉。進程自殺(屬于正常死亡),即使程序出錯,但是進程自身結束了自己,可以通過return和exit賦給進程結束后一個值,通過wait或waitpid函數來獲取該值,從而知道該進程自殺的原因,是否出錯(一般0代表正常,非0代表出錯),當然可以返回任何值,由wait函數可以獲取到。進程如果屬于他殺,則為異常結束,在linux操作系統中,所有的異常終止都是由于某一個信號導致的(通過kill –l參數可以查看所有的信號及信號編號),如在程序中給一個常量賦值,會發生段錯誤,此時進程會收到段錯誤相應的信號,從而被終止;除數為0時,進程也會收到一個信號(浮點數例外),從而被終止。而終止進程的信號會記錄在終止信息中,供父進程調用wait函數獲取。進程死掉后,會留下一具僵尸,wait和waitpid則去收集信息,清理尸體。

exit和_exit這兩個函數(都是系統調用)都有一個整型形參,用于傳遞進程結束時的狀態(正常結束還是出錯結束)。一般,0表示正常結束,非0值(如1)表示出現了錯誤,非正常結束。可以利用wait系統調用接收子進程的返回值,從而針對不同的情況進行不同的處理。

?

pid_t wait(int *status);

status為傳出參數,用于獲取子進程結束時的狀態(原因)。函數執行成功,則返回清理掉的子進程ID,如果失敗則返回-1。進程一旦調用了wait,就立即阻塞自己,由wait自動分析該進程的某個子進程是否已經退出,如果找到了一個已經結束的子進程,則收集其信息,并將其清除掉并返回該子進程ID;如果沒有找到這樣的一個子進程,則會一直阻塞到那里,直到有一個出現為止。如果父進程沒有子進程,則直接返回-1,表示出錯。

如果對子進程如何死掉的不關心(不需要收集其殘留的信息),只想把僵尸進程消滅掉,可以將函數形參設置為NULL,即pid=wait(NULL);

?

可使用wait函數傳出參數status(整型值)來保存進程的退出狀態。借助宏函數來進一步判斷進程終止的具體原因。宏函數可分為如下三組:

?1. WIFEXITED(status) 為非0?? → 表示進程正常結束

WEXITSTATUS(status) 如上宏為真(進程正常結束),使用此宏 → 獲取進程退出狀態 (exit/_exit/return的參數)

?2. WIFSIGNALED(status) 為非0 → 表示進程異常終止

?????? WTERMSIG(status) 如上宏為真,使用此宏 → 取得使進程終止的那個信號的編號。可以通過kill –l命令查看編號的詳細含義。

3. WIFSTOPPED(status) 為非0 → 表示進程處于暫停狀態(進程沒有終止,只是暫停運行,如掛起或阻塞)。

WSTOPSIG(status) 如上宏為真,使用此宏 → 取得使進程暫停的那個信號的編號。

WIFCONTINUED(status) 為真 → 進程暫停后已經繼續運行

?

//代碼舉例

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>int main(void)
{pid_t pid, wpid;int status;pid = fork( );if(pid == 0){printf("---child, my parent= %d, going to sleep 10s\n",getppid( ));sleep(10);printf("-------------child die--------------\n");exit(77); //return 77;  _exit(77);  //子進程正常結束,置其結束狀態為77}else if(pid > 0){wpid = wait(&status);  //父進程阻塞等待子進程結束if(wpid==-1){perror("wait");exit(1); //置結束狀態為1}if( WIFEXITED(status) )  //如果子進程正常結束{printf( "The child process exit with %d\n",WEXITSTATUS(status));}else if( WIFSIGNALED(status) )   //如果子進程異常結束{printf( "The child process was killed by %dth signal\n",WTERMSIG(status));}while (1){printf("I am parent, pid = %d, myson = %d\n", getpid(), pid);sleep(1);}   //父進程一直運行}else{perror("fork");exit(1);}return 0;
}

[root@localhost wait]# ./wait_test

---child, my parent= 30770, going to sleep 10s

-------------child die--------------

The child process exit with 77?? //獲取了結束狀態為77

I am parent, pid = 30770, myson = 30771

I am parent, pid = 30770, myson = 30771

I am parent, pid = 30770, myson = 30771

[root@localhost wait]#ps aux

root????? 30770? 0.0? 0.0?? 4164?? 356 pts/0??? S+?? 18:11?? 0:00 ./wait_test

root????? 30791? 0.0? 0.0 123360? 1380 pts/2??? R+?? 18:12?? 0:00 ps aux

可見,只有父進程在一直運行,子進程不存在了,也不存在僵尸進程,子進程痕跡被完全清除。

?

在子進程運行期間,利用kill -9 將其殺掉,則為異常結束:

[root@localhost wait]#ps aux

[root@localhost wait]# kill 30830

[root@localhost wait]# ./wait_test

---child, my parent= 30829, going to sleep 60s

The child process was killed by 15th signal

I am parent, pid = 30829, myson = 30830

I am parent, pid = 30829, myson = 30830

I am parent, pid = 30829, myson = 30830

I am parent, pid = 30829, myson = 30830

利用kill -l 命令可以查看編號為15的信號為???? 15) SIGTERM

?

總結,進程正常結束,父進程利用wait函數回收其結束狀態,狀態值通過return、exit和_exit返回(一般,如果程序正常則為0,出錯設非0,但不是必須的),如果進程結束沒有指明其值,如main函數中沒有return語句且正常結束,則會有默認值(正常0,出錯非0)。注意,returnexit_exit返回的值必須不超過128可通過wait函數獲取。如果函數異常結束,wait函數回收其終止原因(信號編號)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385358.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385358.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385358.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

map與unordered_map

時間復雜度&#xff1a; mapunordered_mapOrderingincreasing orderno orderImplementationSelf balancing BSTHash Tablesearch timelog(n) O(1&#xff09;: 平均水ping O(n&#xff09;&#xff1a;最糟糕情況 Insertion timelog(n) RebalanceSame sa searchDelete timelo…

waitpid函數

#include <sys/wait.h> #include <sys/types.h> pid_t waitpid(pid_t pid, int *status, int options); 作用&#xff1a;同wait&#xff0c;但可指定pid進程清理&#xff0c;可以不阻塞。 waitpid函數的第二個參數int *status跟wait函數的形參一樣&#xff0c;…

進程間通信的方法

Linux環境下&#xff0c;進程地址空間相互獨立&#xff0c;每個進程各自有不同的用戶地址空間。任何一個進程的全局變量在另一個進程中都看不到&#xff0c;所以進程和進程之間不能相互訪問&#xff0c;要交換數據必須通過內核&#xff0c;在內核中開辟一塊緩沖區&#xff0c;進…

管道的概念(匿名管道)

管道是一種最基本的IPC機制&#xff0c;作用于有血緣關系的進程之間&#xff0c;完成數據傳遞。調用pipe系統函數即可創建一個管道。管道有如下特質&#xff1a;1.其本質是一個偽文件&#xff08;實為內核緩沖區&#xff09;&#xff0c;偽文件即不是真正的文件&#xff0c;不占…

1023. 組個最小數 (20)

給定數字0-9各若干個。你可以以任意順序排列這些數字&#xff0c;但必須全部使用。目標是使得最后得到的數盡可能小&#xff08;注意0不能做首位&#xff09;。例如&#xff1a;給定兩個0&#xff0c;兩個1&#xff0c;三個5&#xff0c;一個8&#xff0c;我們得到的最小的數就…

pipe函數

#include <unistd.h> int pipe(int pipefd[2]); 作用&#xff1a;創建管道 成功&#xff1a;0&#xff1b;失敗&#xff1a;-1&#xff0c;設置errno 函數調用成功返回r/w兩個文件描述符。無需open&#xff0c;但需手動close。規定&#xff1a;fd[0] …

二分查找總結

二分查找法作為一種常見的查找方法&#xff0c;將原本是線性時間提升到了對數時間范圍&#xff0c;大大縮短了搜索時間&#xff0c;具有很大的應用場景&#xff0c;而在LeetCode中&#xff0c;要運用二分搜索法來解的題目也有很多&#xff0c;但是實際上二分查找法的查找目標有…

管道的讀寫行為

使用管道需要注意以下4種特殊情況&#xff08;默認都是阻塞I/O操作&#xff0c;沒有設置O_NONBLOCK標志&#xff09;&#xff1a; 1. 如果所有指向管道寫端的文件描述符都關閉了&#xff08;管道寫端引用計數為0&#xff09;&#xff0c;而仍然有進程從管道的讀端讀數據&#…

【C++ Primer | 08】課后習題答案

文章目錄練習8.13練習8.13 include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> using namespace std;struct PersonInfo {string name;vector<string> phones; };bool valid(const string&…

管道緩沖區大小

可以使用ulimit –a 命令來查看當前系統中創建管道文件所對應的內核緩沖區大小。通常為&#xff1a;pipe size 4K&#xff0c;即一個頁面大小。也可以使用fpathconf函數來查看&#xff1a; #include <unistd.h> long fpathconf(int fd, int name); 當需要查看管道的大…

FIFO(命名管道)

FIFO常被稱為命名管道&#xff0c;以區分管道(pipe)。管道(pipe)只能用于“有血緣關系”的進程間。但通過FIFO&#xff0c;不相關的進程也能交換數據。FIFO是Linux基礎文件類型中的一種&#xff08;p,管道文件&#xff09;。但FIFO文件在磁盤上沒有數據塊&#xff0c;僅僅用來標…

文件進程間通信

使用文件也可以完成IPC&#xff0c;理論依據是&#xff0c;fork后&#xff0c;父子進程共享文件描述符。也就共享打開的文件。 //父子進程共享打開的文件。借助文件進行進程間通信&#xff08;可先打開文件&#xff0c;再創建子進程&#xff09; #include <unistd.h> #…

mmap內存映射、system V共享內存和Posix共享內存

linux內核支持多種共享內存方式&#xff0c;如mmap內存映射&#xff0c;Posix共享內存&#xff0c;以system V共享內存。當內核空間和用戶空間存在大量數據交互時&#xff0c;共享內存映射就成了這種情況下的不二選擇。它能夠最大限度的降低內核空間和用戶空間之間的數據拷貝&a…

mmap、munmap函數

#include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); int munmap(void *addr, size_t length); void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); 返回&#xff1a;成功&…

mmap和munmap對文件進行操作(讀寫等)

//mmap、munmap函數的使用 #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <sys/mman.h>void sys_err(char *str) {perror(str);exit(1); }…

1017. A除以B (20)

本題要求計算A/B&#xff0c;其中A是不超過1000位的正整數&#xff0c;B是1位正整數。你需要輸出商數Q和余數R&#xff0c;使得A B * Q R成立。 輸入格式&#xff1a; 輸入在1行中依次給出A和B&#xff0c;中間以1空格分隔。 輸出格式&#xff1a; 在1行中依次輸出Q和R&#…

mmap父子進程間通信

父子等有血緣關系的進程之間也可以通過mmap建立的映射區來完成數據通信。但相應的要在創建映射區的時候指定對應的標志位參數flags&#xff1a;MAP_PRIVATE&#xff1a;&#xff08;私有映射&#xff09;父子進程各自獨占映射區&#xff1b;MAP_SHARED&#xff1a;&#xff08;…

匿名映射

通過使用我們發現&#xff0c;使用映射區來完成文件讀寫操作十分方便&#xff0c;父子進程間通信也較容易。但缺陷是&#xff0c;每次創建映射區一定要依賴一個文件才能實現。通常為了建立映射區要open一個temp文件&#xff0c;創建好了再unlink、close掉&#xff0c;比較麻煩。…

mmap無血緣關系進程間通信

實質上mmap是內核借助文件幫我們創建了一個映射區&#xff0c;多個進程之間利用該映射區完成數據傳遞。由于內核空間多進程共享&#xff0c;因此無血緣關系的進程間也可以使用mmap來完成通信。只要設置相應的標志位參數flags即可。若想實現共享&#xff0c;當然應該使用MAP_SHA…

【C++ Primer | 13】課后習題答案

文章目錄13.1.4節目練習13.2節練習13.2.2練習13.1.4節目練習 練習13.14 #include <iostream> using namespace std;class numbered { private: static int seq; public:numbered() { mysn seq; }int mysn; };int numbered::seq 0;void f(numbered s) { cout <…