进程等待


首先,让我们先来回顾一下有关进程等待的知识。

所谓进程等待,说的就是父进程等待子进程:

SIGCHLD信号与进程异步等待

如图,父进程调用wait和waitpid函数等待子进程,从而清理系统中的僵尸进程。在此过程中,父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)

若采用阻塞等待方式,父进程就不能处理自己的工作了;采用非阻塞方式,父进程在处理自己工作的同时还要时不时地轮询⼀下子进程状态,程序实现复杂。


SIGCHLD信号


SIGCHLD是linux系统信号列表中定义的第17号信号:

SIGCHLD信号与进程异步等待

事实上,进程等待不只是上面描述的那样,子进程在终止时会给父进程发SIGCHLD信号,因为⼦进程终止是一个异步事件,所以发生这种信号也是内核向父进程发的异步通知。而大多数父进程对该信号的默认处理动作是忽略。

尽管如此,父进程还是可以自定义SIGCHLD信号的处理函数,这样它只需专心处理自己的工作,而不必关⼼子进程了, 子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。


Code


有了进程等待和SIGCHLD信号的概念,接下来利用SIGCHLD信号编写代码实现父进程对子进程的异步等待

1.验证子进程退出时会给父进程发送SIGCHLD信号的机制

代码:先创建子进程,然后使其直接退出。再让父进程调用waitpid和signal函数等待子进程并捕捉子进程发送的17号信号

SIGCHLD信号与进程异步等待

运行结果:

SIGCHLD信号与进程异步等待

结果表明,父进程id为14924的进程确实受到了其子进程退出时发送的17号信号。

2.编写父进程等待子进程的异步版本

上边父进程在等待子进程成功后直接退出,现在我们要实现父进程等待子进程成功后,继续做自己的事情。这就是异步等待。

代码:
在捕捉函数里加入while循环,使得在程序中有多个子进程时,父进程就会一直等待所有子进程退出(id > 0)

SIGCHLD信号与进程异步等待

先让父进程运行,5秒之后子进程退出。父进程等待成功后,继续做自己的事情。

SIGCHLD信号与进程异步等待

运行结果:

SIGCHLD信号与进程异步等待

可以看出,情况如预料的那样。实现了父进程对子进程的异步等待。

但这里有一个问题,如果有子进程一直不退出,那么父进程就会一直阻塞等待。这显然是我们不愿看到的。所以为了解决这个问题,对捕捉函数handler修改如下:

SIGCHLD信号与进程异步等待

在上面的代码中,对waitpid函数的宏参数WNOHANG进行设置,实现非阻塞等待。0和-1都是其可能的返回值,返回0表示没有子进程可以等,返回-1表示函数调用失败。这样就避免了父进程的阻塞等待。所以在while循环里再加入了switch选择分支结构。增强代码的健壮性。

再次运行程序,结果依然无误:

SIGCHLD信号与进程异步等待


The End


关于linux中的信号,以后也会有博文介绍,敬请期待。。。

相关文章:

  • 2022-12-23
  • 2021-08-24
  • 2021-12-31
  • 2022-12-23
  • 2021-10-01
  • 2022-01-22
  • 2021-09-07
猜你喜欢
  • 2021-05-21
  • 2021-05-14
  • 2021-06-26
  • 2021-11-18
相关资源
相似解决方案