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.mzph.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;如&…