阻塞式等待:wait函数,当然waitpid函数当其第三个参数不为WNOHANG时也是阻塞式等待。
非阻塞式等待:(轮询的方式):当waitpid函数当其第三个参数为WNOHANG是非阻塞式等待。
父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)。
若采用阻塞等待方式,父进程就不能处理自己的工作了;采用非阻塞方式,父进程在处理自己工作的同时还要时不时地轮询⼀下子进程状态,程序实现复杂。
SIGCHLD信号:SIGCHLD是l第17号信号.
事实上,进程等待并不是像上边说的那样,而是子进程在终止时会向父进程发SIGCHLD信号,该信号的默认动作是忽略,父进程便可以自定义SIGCHLD信号的处理函数,这样它只需专心处理自己的工作,而不必关⼼子进程了, 子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。
下面来进程编程验证:
1.先来编写子进程退出时会给父进程发送SIGCHLD信号的机制:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<signal.h>
4
5 void handler(int signo)
6 {
7 int count=10;
8 while(count--){
9 printf("get a %d sig,pid:%d\n",signo,getpid());
10 sleep(1);
11 }
12 }
13 int main()
14 {
15 pid_t pid=fork();
16 if(pid<0){
17 perror("fork()");
18 }
19 else if(pid==0){//child
20 printf("child:%d\n",getpid());
21 exit(1);
22 }
23 else{//father
24 signal(SIGCHLD,handler);//父进程捕捉子进程退出时发出的17号信号
25 waitpid(-1,NULL,0);//父进程等待子进程退出
27 }
28 return 0;
29 }
2.父进程异步等待子进程(即为轮询式等待)
上边父进程在等待子进程成功后直接退出,现在我们要实现父进程等待子进程成功后,继续做自己的事情。这就是异步等待。下面我们用非阻塞式等待(轮询的方式)。
下面来解释代码:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<signal.h>
4
5 void handler(int signo)
6 {
7 while(waitpid(-1,NULL,WNOHANG)>0){
8 printf("get a %d sig,pid:%d\n",signo,getpid());//getpid()为父进程的id
9 }
10 printf("child is quit\n",getpid());
11 }
12 int main()
13 {
14 pid_t pid=fork();
15 if(pid<0){
16 perror("fork()");
17 }
18 else if(pid==0){//child
19 printf("child:%d\n",getpid());
20 exit(1);
21 }
22 else{//father
23
24 signal(SIGCHLD,handler);
25 while(1){
26 printf("father %d proc is doing something\n",getpid());
27 sleep(1);
28 }
29 }
30 return 0;
31 }
32
结果展示:
可以看出实现了父进程对子进程的异步等待。