父进程等待子进程的异步版本
程序员文章站
2022-05-14 19:30:58
...
前言
首先,打开linux虚拟机或者系统的时候,系统自己建立一个init进程,这是Linux系统的基础进程,然后init进程再根据一些配置文件决定创建哪些进程,或者我们在终端自己创建一个新进程的时候,如果你有时间,你可以一直追查这个进程的祖祖辈辈,你会发现,他们都指向一个进程,那就是init进程。所以,可以这么说,Linux系统服务中,所有进程都是init的子孙进程。所以,进程的创建是通过创建子进程一个一个实现的。
但是,一味的创建进程,而不对进程进行合理的管理,必然会造成操作系统的冗余,长时间下来,因为无用进程过多,系统将会崩溃。因为每个进程需要对自己维护一个PCB的结构体,来描述一个进程所有可能用到的资源、标志…所以,这个结构体并不小,且每个进程都自己私有一个,所以对无用进程的PCB管理是很有必要的。
操作系统把无用或退出进程的PCB管理交给了他的父进程,每个拥有子进程的父进程函数体中都有一个等待操作,需要对他创建的子进程进行管理,毕竟,父亲管儿子天经地义嘛!所以,父进程在执行完自己的所有操作后,会以阻塞或者轮询的方式等待子进程的退出,收到子进程的退出数据之后,通过一定的手段,对子进程的PCB进行资源的释放。
验证子进程退出时给父进程发送信号
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void handler(int sig)
{
printf("%d\n",sig);
}
int main()
{
int i=1;
for(;i<=31;i++){
signal(i,handler);
}
printf("\n");
pid_t id=fork();
if(id<0){
perror("fork");
exit(1);
}else if(id==0){
printf("i am a child:%d,my father is %d\n",getpid(),getppid());
exit(2);
}
printf("i am father:%d\n",getpid());
sleep(1);
return 0;
}
使用signal函数实现对信号的捕捉,捕捉到17号信号,即SIGCHLD信号。
程序运行结果:
父进程先退出,子进程退出之后给父进程发送一个信号。
现在已经验证子进程退出时会对父进程发出一个SIGCHLD的信号,所以我们可以对这个信号进行捕捉,自定义的信号处理方式表位等待一个子进程,所以这就省去了对于一个子进程的阻塞等待或者轮询等待时资源的耗费。
代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<signal.h>
void catchSig(int sig)
{
do{
pid_t ret = waitpid(-1,NULL,WNOHANG);
if(ret>0){
printf("wait success:%d\n",ret);
}else{
printf("wait failed\n");
break;
}
}while(1);
}
int main()
{
signal(SIGCHLD,catchSig);
pid_t id = fork();
if(id==0){
//child
printf("i am child! pid:%d\n",getpid());
sleep(4);
exit(1);
}else{
while(1)
{
printf("do father things!\n");
sleep(1);
}
}
return 0;
}
输出结果: