为什么要进程等待
这又得说到僵尸进程了https://blog.csdn.net/cx2479750196/article/details/79963888,
总结的来说,就是子进程退出,但是让子进程帮忙做事的父进程一直不查看子进程做事的结果,所以子进程进入僵尸状态,我们可以通过杀死父进程来退出此状态(但是很暴力),所以我们可以采取让父进程等待,让他记得要回收子进程资源,获取子进程的退出信息。
父进程是怎么等待的呢?
1、wait()方法
#include<sys/types.h> #include<sys/wait.h> pid_t waitZ(int* status);
成功返回的是被等待进程的pid,失败返回-1
参数是输出型参数,获取子进程的状态,不关心状态时可以设置成NULL
2、waitpid()方法
pid_t waitpid(pid_t pid,int * status,int options);
正常返回子进程的id
参数pid:pid==-1,等待任意子进程,和wait一样
pid>0:等待其进程id与pid相等的子进程
status:
WIFEXITED(status):如果是正常终止子进程返回的状态,则为真
WEXITSTATUS(status):如果WIFEXITED非零,提取子进程退出码
具体思路:
分析:两种方法都需要获取子进程status来作为返回值,如何获取返回值??
获取子进程status
status参数是由操作系统填充的,如果传递NULL,表示不关心状态,否则,操作系统会根据该参数将子进程的退出信息反馈给父进程。要将status看做成位图。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
int main(){
pid_t pid=fork();
if(pid<0){
perror("fork()");
}
else if(pid==0){
//child
sleep(20);
exit(10);//期望后面打印10
}else{
//father
int st;
int ret=wait(&st);//不关心子进程退出状态时wait(NULL);
if(ret<0){
printf("error");
}
else {
if((st&0x7f)==0){//正常退出
printf("exit code:%d\n",(st>>8)&0xff);
}
else{
printf("sig code:%d\n",st&0x7f);
}
}
}
}
父进程只能等待一个进程,如果wait与子进程个数不匹配,那么有的子进程就会陷入僵尸进程
1 #include<unistd.h>
2 #include<stdlib.h>
3 #include<stdio.h>
4
5 #include<sys/wait.h>
6 int main(){
7 printf("father:%d\n",getpid());
8 pid_t id=fork();
9 if(id==0){
10 //第一个子进程
11 printf("child:%d\n",getpid());
12 sleep(3);
13 exit(0);
14 }
15 //父进程
16 id=fork();
17 if(id==0){
18 //第二个子进程
19 printf("child:%d\n",getpid());
20 sleep(5);
21 exit(0);
22 }
23 wait(NULL);
24 // wait(NULL);
25 // printf("father do other thing");//只有一个wait()时就会有僵尸进程产生
26 while(1){
27 sleep(1);
28 return 0;
29 }
30 }
演示waitpid方法:
2、waitpid()方法
pid_t waipid(pid_t pid,int* status,int options);
返回值:
正常返回返回的是子进程的id
参数pid:
pid==-1,等待任意子进程,和wait一样
pid>0:等待其进程id与pid相等的子进程status:
status:
WIFEXITED(status):如果是正常终止子进程返回的状态,则为真查看进程是否正常退出
WEXITSTATUS(status):如果WIFEXITED非零,提取子进程退出码查看退出码
options:
WNOHANG:如果pid指定子进程没有结束,则waitpid()返回0,不再等待,正常结束则返回子进程的id.
阻塞式等待:(父进程在等子进程子进程一天不结束父进程就无法往下执行)
1 #include<sys/wait.h>
2 #include<stdio.h>
3 #include<stdlib.h>
4 #include<string.h>
5 #include<errno.h>
6 int main(void){
7
8 pid_t pid=fork();
9 if(pid<0){
10 perror("fork"),exit(1);
11 }
12 else if(pid==0){
13 //child
14 printf("child if run,pid:%d\n",getpid());
15 sleep(5);//阻塞式等待。等待5s
16 exit(257);
17 }
18 else{
19 //father
20 int st=0;
21 pid_t ret=waitpid(-1,&st,0);//-1表示等待任意进程,正常返回子进程id,如果没有已退出的子进程返回0,调用出错返回-1.
22 printf("this is test for wait\n");
23 if(WIFEXITED(st)&&ret==pid){//WIFEXITED(st)在正常终止子进程的时候才为真。
24 printf("wait child is sucess,child return %d\n",WIFEXITED(st));
25 }else{
26 printf("wait child failed");
27 return 1;
28 }
29 }
30 return 0;
31 }
非阻塞时等待:
#include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4 #include<sys/wait.h>
5 int main(){
6 pid_t pid=fork();
7 if(pid<0){
8 perror("fork()");
9 return 1;
10 }
11 else if(pid==0){
12 //child
13 sleep(10);
14 exit(10); printf("child ifs run");
15 }
16 else{
17 //father
18 int st=0;
19 int ret=0;
20 do{
21 ret=waitpid(-1,&st,WNOHANG);
22 if(ret==0){//没有已退出的子进程可以收集
23 printf("child is running\n");
24 }
25 sleep(1);
26 }while(ret==0);//只要有子进程没有结束就要一次次进去查看状态
27
28 if(WIFEXITED(st)&&ret==pid){//正常退出的状态下
29 printf("child exit code:%d\n",WEXITSTATUS(st));
30 }
31 else{
32 printf("wait failed\n");
33 return 1;
34 }
35 }
36 return 0;
37 }