子进程的异步等待方式

来源:互联网 发布:电影资源知乎 编辑:程序博客网 时间:2024/06/07 11:51

原来只给大家介绍过僵尸进程,而没有介绍僵尸进程是怎么回收的,今天就给大家介绍一下如何回收僵尸进程。

用wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)。采用第一种方式,父进程阻塞了就不能处理自己的工作了;采用第二种方式,父进程在处理自己的工作的同时还要记得时不时地轮询一下(也就是过一段时间过来看一下是否有子进程退出然后回收它)。

其实,子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。

下面我们用自定义的信号捕捉函数来捕捉SIGCHLD信号。先让父进程fork出一个子进程,让子进程sleep3秒之后在退出,这时候我们对SIGCHLD信号进程捕捉,打印出我们想要的语句,这样就可以验证子进程会对父进程发送SIGCHLD信号。

测试如下:

#include <stdio.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>void handler(int sig){    printf("sig is: %d\n", sig);}int main(){    signal(SIGCHLD, handler);    pid_t id = fork();    if(id == 0)    {        printf("child is: %d, father is: %d\n", getpid(), getppid());        exit(0);    }    else    {        printf("father is: %d\n", getpid());        sleep(3);    }    return 0;}

在上面的代码中我们让子进程先退出,这是我们对SIGCHLD信号进行了捕捉,然后在我们的捕捉函数中打印了捕捉的信号为17,而在下面我们可以看出17号信号为SIGCHLD。

父进程等待子进程的异步版本 :

首先必须介绍waitpid这个函数:

pid_t waitpid(pid_t pid, int *status, int options);
参数1:pid

Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
Pid==0等待其组ID等于调用进程组ID的任一个子进程。
Pid<-1等待其组ID等于pid绝对值的任一子进程。
参数2:status

WIFEXITED(status) : 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status) : 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

参数3:options

WNOHANG:非阻塞式等待指定的进程。

WUNTRACED:如果子进程进入暂停执行则马上返回,但结束状态不予以例会。

WCONTINUED:若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但状态尚未报告,则返回状态。

下面我们直接测试子进程的已步等待方式

将waitpid的第一个参数设置为-1等待任何一个子进程,将参数3设置为WNOHANG非阻塞是等待进程。

#include <stdio.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>void handler(int sig){    pid_t id ;    while((id = waitpid(-1,NULL,WNOHANG)) > 0)    {        printf("father:wait success:%d\n",id);     }    printf("child is quit! %d\n",getpid());}int main(){    signal(SIGCHLD, handler);    pid_t id1 = fork();    if(id1 == 0)    {        printf("child is: %d, father is: %d\n", getpid(), getppid());        exit(0);    }    pid_t id2 = fork();    if(id2 == 0)    {        printf("child is: %d, father is: %d\n", getpid(), getppid());        sleep(1);        exit(0);    }    printf("father is: %d\n", getpid());    while(1)    {        printf("father is wait\n");        sleep(1);    }    return 0;}



在上面的代码中我们可以看出两个子进程分别是2907和2906,父进程为2905。当进程2069进程直接退出后给父进程发送了SIGCHLD信号,这时候父进程捕捉到了子进程发送的信号并打印了子进程的id 2906,然后打印自己的id 2905,等待了1秒后子进程2907退出给父进程发送了信号SIGCHLD,然后父进程接受并打印。






原创粉丝点击