#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status)
功能:等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收子进程。
参数:int *status
进程退出时的状态信息,传入的是一个int类型的地址,传出参数。
返回值:
-成功:返回被回收的子进程的id
-失败:-1(等所有的子进程都结束后,证明函数调用失败,所以返回-1).
调用wait()函数的进程会被挂起(阻塞),直到它的一个子进程退出或者收到一个不能被忽略的信号才能被唤醒(相当于继续往下执行);
如果没有子进程,函数会立即返回-1;如果子进程已经结束了,也会立即返回-1.
下面的创建了5个fork(),先观察什么结果。
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/stat.h>
4 #include <unistd.h>
5 int main()
6 {
7 pid_t pid;
8 for(int i=0;i<5;i++)
9 {
10 pid=fork();
11 if(pid==0)
12 {
13 break;
14 }
15 }
16 if(pid>0)
17 {
18 while(1)
19 {
20 printf("parent:%d\n",getpid());
21 sleep(1);
22 }
23 }
24 else if(pid==0)
25 {
26 printf("child:%d\n",getpid());
27 }
28 return 0;
29
30 }
运行结果如下:
child:54384
child:54385
parent:54383
child:54387
child:54388
child:54386
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
parent:54383
通过观察就可以发现,通过调用五次fork()函数,出现了五次子进程id,随即就都是父进程了,也就是说出现五次子进程id后就死掉了,也可以通过ps aux来查看
Z+呈现出僵死的状态,如果CTRL+C,重新查看ps aux就不会出现僵死的状态了,此时就会被进程号为1的init给回收了。
接下来,加入我们的主角wait(),看看有什么效果,让我们拭目以待
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/stat.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 int main()
7 {
8 pid_t pid;
9 for(int i=0;i<5;i++)
10 {
11 pid=fork();
12 if(pid==0)
13 {
14 break;
15 }
16 }
17 if(pid>0)
18 {
19 while(1)
20 {
21 printf("parent:%d\n",getpid());
22 int ret=wait(NULL);
23 printf("child die,pid=%d\n",ret);
24 sleep(1);
25 }
26 }
27 else if(pid==0)
28 {
29 while(1)
30 {
31 printf("child:%d\n",getpid());
32 sleep(1);
33 }
34 }
35 return 0;
36
37 }
注意观察,我在父进程中加入了wait()函数,因为调用wait()函数的进程会被挂起(阻塞),所以当程序运行到时,父进程就被挂起了(相当于退出),然后去运行子进程了
通过截图可以看出父进程只运行了一次。如果此时我杀死一个进程kill -9 5417,那么出现了
说明在刚刚父进程阻塞的地方现在变得不阻塞了,将继续往下运行,如果全部杀死后,就没有子进程了,那么此时就变成了-1.自己可以动手操作一下。
另外,还有一些退出信息相关的宏函数
WIFEXITED(status)-->为真-->调用WEXITSTATUS(status)-->得到 子进程 退出值。
(作用:判断是不是正常退出)
WIFSIGNALED(status)-->为真-->调用WTERMSIG(status)-->得到 导致子进程异常终止的信号编号。
(作用:判断被哪个信号给干掉了)
接下来我们一步一步操作(只插入主函数)
7 int main()
8 {
9 pid_t pid;
10 for(int i=0;i<5;i++)
11 {
12 pid=fork();
13 if(pid==0)
14 {
15 break;
16 }
17 }
18 if(pid>0)
19 {
20 while(1)
21 {
22 printf("parent:%d\n",getpid());
23 int st;
24 int ret=wait(&st);
25 if(ret==-1)
26 {
27 break;
28 }
29 if(WIFEXITED(st))
30 {
31 printf("退出的状态码:%d\n",WEXITSTATUS(st));
32 }
33 if(WIFSIGNALED(st))
34 {
35 printf("被那个信号给干掉了:%d\n",WTERMSIG(st));
36 }
37 printf("child die,pid=%d\n",ret);
38 sleep(1);
39 }
40 }
41 else if(pid==0)
42 {
43 printf("child:%d\n",getpid());
44 sleep(1);
45 exit(0);
46 }
47 return 0;
48
49 }
运行结果:退出状态码是由exit(0)决定的,如果exit(1).则退出状态码就是1.
当我把子进程放进死循环中,然后kill -9 子进程id,此时变成了
获取了被哪个信号给干掉了。真棒