子进程的异步等待方式

xiaoxiao2021-02-28  140

基础知识

在前面的博客中我们已经介绍了僵尸进程(僵尸进程与孤儿进程)的相关知识,我们说过可以通过调用wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以以非阻塞的查询是否有子进程结束等待清理(也就是轮询的方式)

wait与waitpid函数

1.wait函数

#include<sys/types.h> #include<sys/wait.h> pid_t wait(int* status)

函数说明: 进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。 参数: 参数 statloc 是一个整形指针。如果status不是一个空指针,则终止进程的终止状态将存储在该指针所指向的内存单元中。如果不关心终止状态,可以将 status参数设置为NULL。 返回值: 如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno 中。 2.waitpid

#include<sys/types.h> #include<sys/wait.h> pid_t waitpid(pid_t pid,int* status,int options);

函数说明: 从本质上讲,系统调用waitpid和 wait的作用是完全相同的,但waitpid多出了两个可由用户控制的参数pid和options,从而为我们编程提供了另一种更灵活的方式。 参数: (1)pid:从参数的名字pid和类型 pid_t中就可以看出,这里需要的是一个进程ID。但当pid取不同的值时,在这里有不同的意义。

pid>0时,等待进程ID等于 pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。

(2)ststus与wait()函数的参数基本相同。 (3)options: 当options参数为0时,与wait功能相同,仍是阻塞式等待,不提供额外功能,如果为下列常量按位或则提供更多功能: WCONTINUED:若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但状态尚未报告,则返回状态 WNOHANG:若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,即此时以非阻塞方式(轮询式访问的必要条件)等待子进程,并且返回0。 WUNTRACED:若实现支持作业控制,而pid指定的任一子进程已经暂停,且其状态尚未报告,则返回其状态 返回值: waitpid的返回值比wait稍微复杂一些,一共有3种情况:

当正常返回的时候,waitpid返回收集到的子进程的进程ID;如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0; 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这时errno被设置为ECHILD;3.waitpid提供了三个wait所没有的功能:waitpid可等待一个特定的进程waitpid提供了一个wait的非阻塞版本waitpid支持作业控制

SIGCHLD

SIGCHLD信号:当子进程退出时,它会向父进程发送SIGCHLD信号,该信号的默认处理方式为忽略,当父进程以阻塞方式等待时,它不能处理自己的工作。 我们自定义一个捕捉信号的函数handler。

验证子进程退出时会给父进程发送SIGCHLD信号

#include<stdio.h> #include<unistd.h> #include<sys/types.h> #include<sys/wait.h> #include<stdlib.h> //子进程退出时,会给父进程发送SIGCHLD信号 void handler(int sig) { printf("Get a sig: %d,pid: %d\n",sig,getpid()); } int main() { signal(SIGCHLD,handler); pid_t id = fork(); if(id == 0) { //child printf("I am a child,quit! pid %d\n",getpid()); exit(1); } else { //father waitpid(id,NULL,0); // 以阻塞方式等待 } return 0; }

父进程等待子进程的异步方式

父进程自定义SIGCHLD信号的处理函数,并采用非阻塞方式等待,当子进程退出时,会向父进程发送信号,父进程会进行回收。父子进程互不干扰,继续执行各自任务。

验证代码

#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/wait.h> //父进程等待子进程的异步方式 void handler(int sig) { printf("father is catching,child is quit!\n"); //以阻塞方式等待所有异常退出的子进程 pid_t id; while((id = waitpid(-1,NULL,WNOHANG)) > 0) { printf("wait child success: %d\n",id); } } int main() { signal(SIGCHLD,handler); pid_t id = fork(); if(id == 0) { //child printf("I a child,quit! pid: %d\n",getpid()); exit(1); } else { //father while(1) { printf("father is doing something!\n"); sleep(1); } } return 0; }

转载请注明原文地址: https://www.6miu.com/read-30492.html

最新回复(0)