本文共 1122 字,大约阅读时间需要 3 分钟。
首先,让我们先来回顾一下有关进程等待的知识。
所谓进程等待,说的就是父进程等待子进程:
如图,父进程调用wait和waitpid函数等待子进程,从而清理系统中的僵尸进程。在此过程中,父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)。
若采用阻塞等待方式,父进程就不能处理自己的工作了;采用非阻塞方式,父进程在处理自己工作的同时还要时不时地轮询⼀下子进程状态,程序实现复杂。
SIGCHLD是linux系统信号列表中定义的第17号信号:
事实上,进程等待不只是上面描述的那样,子进程在终止时会给父进程发SIGCHLD信号,因为⼦进程终止是一个异步事件,所以发生这种信号也是内核向父进程发的异步通知。而大多数父进程对该信号的默认处理动作是忽略。
尽管如此,父进程还是可以自定义SIGCHLD信号的处理函数,这样它只需专心处理自己的工作,而不必关⼼子进程了, 子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。
有了进程等待和SIGCHLD信号的概念,接下来利用SIGCHLD信号编写代码实现父进程对子进程的异步等待。
1.验证子进程退出时会给父进程发送SIGCHLD信号的机制
代码:先创建子进程,然后使其直接退出。再让父进程调用waitpid和signal函数等待子进程并捕捉子进程发送的17号信号
运行结果:
结果表明,父进程id为14924的进程确实受到了其子进程退出时发送的17号信号。
2.编写父进程等待子进程的异步版本
上边父进程在等待子进程成功后直接退出,现在我们要实现父进程等待子进程成功后,继续做自己的事情。这就是异步等待。
代码:
在捕捉函数里加入while循环,使得在程序中有多个子进程时,父进程就会一直等待所有子进程退出(id > 0)先让父进程运行,5秒之后子进程退出。父进程等待成功后,继续做自己的事情。
运行结果:
可以看出,情况如预料的那样。实现了父进程对子进程的异步等待。
但这里有一个问题,如果有子进程一直不退出,那么父进程就会一直阻塞等待。这显然是我们不愿看到的。所以为了解决这个问题,对捕捉函数handler修改如下:
在上面的代码中,对waitpid函数的宏参数WNOHANG进行设置,实现非阻塞等待。0和-1都是其可能的返回值,返回0表示没有子进程可以等,返回-1表示函数调用失败。这样就避免了父进程的阻塞等待。所以在while循环里再加入了switch选择分支结构。增强代码的健壮性。
再次运行程序,结果依然无误:
关于linux中的信号,以后也会有博文介绍,敬请期待。。。