小说python中的孤儿进程

僵尸进程,大家都会对其嗤之以鼻,敬而远之,毕竟臭名在外。

孤儿进程,大家对其都很宽容,甚至可以说是放纵,只因系统会收留。

然而,在实际应用中,孤儿进程虽然不会给系统造成直接性的危害,但更多时候会对业务造成一些影响,如当子进程为一个基于tcp的socket服务时,会造成主进程再次启动时无法启动,端口被占用。主进程退出了,子进程会因为无法获得某些资源,而变成业务上的"僵尸进程",这实际也是资源浪费。对于一些有进程监控的服务来说,可能会造成业务主服务无法重启,或是进程不可控。

鉴于这些情况下,很多时候是不希望产生孤儿进程的,子进程应随父进程结束而结束。

本文就小说一把如何做一个有担当的"父亲",不要不负责任的"一走了之",随意丢弃自己的"孩子们"。

什么是孤儿进程

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成中止后的资源回收工作

通过下面的具体例子,具体看看

centralized_in_out服务会启动8个子进程,父进程ID为5310,子进程ID为5312-5319

将父进程(5310)kill掉,可以看到子进程5312-5319全由ID为1的进程接管

如何做

上面看到子进程5312-5319被init进程接管了,但这不是我想要的结果,当前业务中,会再次拉起centralized_in_out服务,会再启动8个子进程,这样进程数太多,会失控,不符合业务需求。

我需要的是”父子共进退“,如何做呢?

豆瓣的工程师们,已经给出了解决办法,具体参见:

https://github.com/douban/CaoE

修改代码,用起来,效果如下

为什么

豆瓣工程师给出了解决办法,不能只拿来用用,得问几个为什么?通过什么实现的?为什么要这么做呢?

下面具体分析下实现方法:

1. 方法概述

实现思路是通过创建一个子进程和孙子进程,子进程会监控父进程的状态,当检测到父进程退出后,会给进程组发送信号通知杀死孙子进程及其子进程。

这里涉及到进程组信号两个重要概念,下面具体阐述。

2. 概念阐述

进程组:每个进程都会属于一个进程组(process group),每个进程组中可以包含多个进程。进程组会有一个领导进程 (process group leader),领导进程的PID成为进程组的ID (process group ID, PGID),用来标识进程组。

如下图所示,centralized_in_out服务父进程的ID为5538(它的PGID为5538),子进程ID为5540(它的PGID为5540),孙子进程的ID为5541(它的PGID为5540),孙孙进程5542-5549的PGID都为5541

信号:具体概念这里不多说了,有些大,而且晦涩难懂。主要涉及信号定义和处理函数的注册绑定,后面结合代码具体说明

3. 实现详解

通过两次fork,创建子进程(ID:5540)和孙进程(ID:5541),

其中子进程中有重要的一步,os.setpgrp()将子进程的进程组ID(5540)设为当前进程组的ID,后面孙进程和孙孙进程的进程组ID都为5540。

子进程在exit_when_parent_or_child_dies方法中循环等待父进程状态,当PPID为1时,说明父进程已退出,通过killpg()将进程组中的所有进程(孙孙进程)杀死,然后自己退出。

到此,整个流程就清晰了,通过设置孙进程和孙孙进程的进程组ID为子进程的进程ID,当主进程退出,子进程被init进程接管时,通过killpg将同一个进程组ID的孙进程和孙孙进程中止。

但如果仔细看代码,

exit_when_parent_or_child_dies方法中:

if os.getppid() == 1: 永远执行不到,因为父进程退出时,捕获如下信号

而这些信号处理方法中都会通过killpg杀死进程组,子进程也属于这个进程组,也会被kill掉。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180814G1SS0Y00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券