waitpid函數

#include <sys/wait.h>

#include <sys/types.h>

?

pid_t waitpid(pid_t pid, int *status, int options);

作用:同wait,但可指定pid進程清理,可以不阻塞。

waitpid函數的第二個參數int *status跟wait函數的形參一樣,且都是利用相同的宏函數來進一步獲取結束進程的狀態和終止原因。

第一個形參pid>0,則回收指定參數(pid)的PID進程;=-1,則回收該父進程的任意一個子進程,相當于wait函數;=0,則回收和當前調用waitpid函數一個組的任意子進程(即跟父進程在同一個組的所有子進程);<-1,則回收指定進程組內的任意子進程。因此,-1的范圍最大,所有子進程;其次是小于-1和0,最后是指定具體的子進程。注意,wait函數和waitpid函數只能回收父進程自己的子進程,且一次waitwaitpid調用只能清理一個子進程,清理多個子進程應使用循環。在默認情況下,父進程fork后產生的子進程跟父進程在同一個進程組,因此參數為0時,在這種情況下,相當于回收fork產生的所有子進程。

再次強調:一次wait或waitpid調用只能回收一個子進程,如果回收的是多個子進程,則哪一個子進程先結束,則回收哪一個。如果都回收,則可以采用循環(for、while、do while等)。

第三個參數options為0,則代表阻塞等待子進程結束,再回收,跟wait一樣;為WNOHANG,則不再等待,如果要回收的子進程都在運行,則直接返回0,然后接著執行后續程序;為WUNTRACED,如果子進程由于被停止產生的SIGCHLD,waitpid則立即返回;為WCONTINUED,如果子進程由于被SIGCONT喚醒而產生的SIGCHLD,waitpid則立即返回。

對于waitpid的返回值:如果沒有子進程或其它錯誤原因,則返回-1;如果成功回收子進程,則返回回收的那個子進程的ID;如果第三個參數為WNOHANG,且子進程都在運行,則返回0。

因此:waitpid( -1, NULL,0) 與 wait( NULL )是等效的,都是阻塞等待回收所有子進程。

?

//代碼

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>int main(void)
{pid_t pid, pid2, wpid;int flg = 0;pid = fork();pid2 = fork();  //此時總共有4個進程(不包括shell)if(pid == -1){perror("fork error");exit(1);} else if(pid == 0){  //注意:pid=0的進程有兩個,子進程和子進程的子進程printf("I'm process child, pid = %d\n", getpid());sleep(5);exit(4);} else {        //注意:pid>0的進程有兩個,父進程和子進程do {wpid = waitpid(pid, NULL, WNOHANG);printf("---wpid = %d--------%d\n", wpid, flg++);if(wpid == 0){printf("NO child exited\n");sleep(1);}} while (wpid == 0);            //子進程不可回收if(wpid == pid){                //回收了指定子進程printf("I'm parent, I catched child process,""pid = %d\n", wpid);} else {printf("other...\n");}}return 0;
}

[root@localhost wait]# ./waitpid

---wpid = 0--------0

NO child exited

I'm process child, pid = 33493

---wpid = -1--------0

I'm process child, pid = 33495

other...

---wpid = 0--------1

NO child exited

---wpid = 0--------2

NO child exited

---wpid = 0--------3

NO child exited

---wpid = 0--------4

NO child exited

---wpid = 33493--------5

I'm parent, I catched child process,pid = 33493

?

?

//代碼:阻塞回收一個子進程

#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>int main(int argc, char *argv[])
{int n = 5, i;                           //默認創建5個子進程pid_t p, q;if(argc == 2) {n = atoi(argv[1]);  //將字符串轉化為整數}for(i = 0; i < n; i++) {//出口1,父進程專用出口p = fork();if(p == 0)break;                  //出口2,子進程出口,i不自增else if (i == 3){q = p;   //將第4個子進程的ID保存在q中}}if(n == i){sleep(n);printf("I am parent, pid = %d\n", getpid());pid_t pid = waitpid(-1,NULL,0); //等價于 pid_t pid = wait(NULL);if( pid == -1){perror("waitpid");exit(1);}while(1);  //讓父進程陷入死循環,防止子進程被init回收} else {sleep(i);printf("I'm %dth child, pid = %d\n", i+1, getpid());}return 0;
}

//代碼:阻塞回收指定的進程(第4個子進程)if(n == i){sleep(n);printf("I am parent, pid = %d\n", getpid());//pid_t pid = waitpid(-1,NULL,0); //等價于 pid_t pid = wait(NULL);pid_t pid = waitpid(q,NULL,0);
if( pid == -1){perror("waitpid");exit(1);}while(1);  //讓父進程陷入死循環,防止子進程被init回收} else {sleep(i);printf("I'm %dth child, pid = %d\n", i+1, getpid());}//代碼:阻塞回收所有的子進程if(n == i){sleep(n);printf("I am parent, pid = %d\n", getpid());//pid_t pid = waitpid(-1,NULL,0); //等價于 pid_t pid = wait(NULL);//pid_t pid = waitpid(q,NULL,0);while(waitpid(-1,NULL,0)); // 等價于while(wait(NULL));while(1);  //讓父進程陷入死循環,防止子進程被init回收
認回收} else {sleep(i);printf("I'm %dth child, pid = %d\n", i+1, getpid());}//代碼:非阻塞(WNOHANG)回收所有的子進程if(n == i){sleep(n);printf("I am parent, pid = %d\n", getpid());//pid_t pid = waitpid(-1,NULL,0); //等價于 pid_t pid = wait(NULL);//pid_t pid = waitpid(q,NULL,0);//while(waitpid(-1,NULL,0)); // 等價于while(wait(NULL));do{
pid_t pid = waitpid(-1,NULL,WNOHANG);if ( pid > 0 )n--;}while( n > 0 )while(1);  //讓父進程陷入死循環,防止子進程被init回收} else {sleep(i);printf("I'm %dth child, pid = %d\n", i+1, getpid());}

[root@localhost wait]# ps aux

root????? 34224 57.1? 0.0?? 4164?? 356 pts/0??? R+?? 22:58?? 0:06 ./loop_fork

root????? 34230? 0.0? 0.0 123360? 1380 pts/2??? R+?? 22:58?? 0:00 ps aux

可以看到,所有子進程都被回收,沒有僵尸進程。

當第一個參數為-1時,為指定進程組:

[root@localhost wait]# ps ajx

? PPID?? PID?? PGID??? SID TTY???? TPGID ?STAT?? UID?? TIME COMMAND

?? ?0????? 2????? 0????? 0 ???????????? -1 ????S??????? 0?? 0:00 ?[kthreadd]

ps ajx指令:PPID為父進程ID;PID為進程ID;PGID為進程組ID。SID為會話ID。

[root@localhost wait]# cat | cat | cat | cat?? //執行這個命令,然后查看進程組ID

[root@localhost wait]# ps ajx

29904? 34326? 34326? 29904 pts/0???? 34326 S+?????? 0?? 0:00 cat

?29904? 34327? 34326? 29904 pts/0???? 34326 S+?????? 0?? 0:00 cat

?29904? 34328? 34326? 29904 pts/0???? 34326 S+?????? 0?? 0:00 cat

?29904? 34329? 34326? 29904 pts/0???? 34326 S+?????? 0?? 0:00 cat

可以看到這四個進程的進程組ID都一樣,屬于同一個進程組,為34326。因此要回收這四個子進程,第一個參數為:-34326。 ?要殺死這四個進程: kill -34326或kill -9 -34326

練習作業:父進程fork 3 個子進程,三個子進程一個調用ps命令, 一個調用自定義程序1(正常),一個調用自定義程序2(會出段錯誤)。父進程使用waitpid對其子進程進行回收,并指出其狀態和退出的原因。

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

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

相關文章

進程間通信的方法

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 <…

信號的概念與機制

信號的共性&#xff1a;1. 簡單&#xff08;開銷小&#xff0c;且在用或者不用的情況下&#xff0c;開銷是一樣的&#xff09;&#xff1b;2. 不能攜帶大量信息&#xff08;如程序執行過程中&#xff0c;出現段錯誤時&#xff0c; 就會發送一個相關的信號&#xff08;編號為11&…

信號的產生和狀態

信號的產生&#xff1a;1.按鍵產生&#xff0c;如&#xff1a;Ctrlc&#xff08;內核向進程發送信號&#xff0c;殺死該進程&#xff09;、Ctrlz、Ctrl\&#xff1b;2.系統調用產生&#xff0c;如&#xff1a;kill、raise、abort&#xff1b;3.軟件條件產生&#xff0c;如&…