• fork() & 僵尸进程


    上周,项目里需要一个视频转发工具,我用libvlc完成了一个,大致流程如下:

    (1)主进程监听指定端口,接收转发请求;

    (2)验证请求合法性后,主进程fork一个子进程,在子进程中启动vlc进行转发。

    但调试时发现了一个小问题:

    fork出子进程后,在父进程中没有调用waitpid,在子进程退出后, 父进程没有为它“收尸”。于是乎,子进程虽然退出了,但进程号在系统历仍然存在,变成了臭名昭著的“僵尸进程”。

    问题的根源在于:父进程没有调用waitpid来监测子进程的活动状况,关于waitpid能干什么,请搜索之。。。

    但是:父进程是单线程(称为监听线程),主要干一件事,那就是调用socket的recvfrom(),阻塞的监听网络请求; 因此,不可能用来调用waitpid来为子进程收尸。

    有四个办法解决: 

    (一)在父进程监听线程中给socket设超时,每次超时后就调用waitpid(使用NOHANG参数,免得主进程被挂住)来查看一下子进程的状态。如果子进程退出了,就为它收尸;否则就继续recrfrom,监听请求。

    主要问题有两个:(1)子进程退出后,必须等到recvfrom超时后,父进程才会调用waitpid,才会知道子进程已经退出了,从而为它收尸;

    (2)虽然调用waitpid时间很短,但也会造成recvfrom()暂时中断;如果这段时间刚好有网络请求过来,父进程就很可能接收不到该请求,造成服务无响应,这种情况必须避免。

    (二)父进程中再开一个线程(简称监测线程),使用waitpid()专门检测子进程的状态(不使用NOHANG参数,一直挂在waitpid上),实际上我在录制程序中就是这么干的(主要是为了实现子进程崩溃时,由父进程自动重启子进程)。

    问题在于:监测线程中检测到子进程退出后,我还需要从父进程中查找子进程列表,确认是那一路节目退出了;这样就必须加锁,因为监听线程随时可能访问子进程列表。

    这样一来,就遇到了棘手的问题:多线程+加锁+fork()多进程,这正是我尽力避免的一种情况 。

     

    (三) 在父进程中忽略SIGCLD信号,就不会产生僵尸进程了,具体如下:

     signal(SIGCLD, SIG_IGN); /* now I don't have to wait()! */  

    但是,当我在子进程中启动libvlc 进行视频转发时,发现无法启动vlc,经过跟踪,确认子进程在初始化libvlc时挂住了:

    _vlcinstance = libvlc_new(sizeof (vlc_args) / sizeof (vlc_args[0]), vlc_args, &_vlcexcep); //Calculation character space

    具体就是调用libvlc_new()时,原因未知,推测可能是libvlc内部对该信号量做了某种处理,导致挂死。

     

     (四)父进程中,连续fork()两次,立即退出子进程,使孙进程成为“孤儿进程”,被系统的init进程管理;这样,孙进程退出时,init进程会负责为它收尸,就不会产生僵尸进程了。

     虽然听起来不错,但总归有点投机取巧。

     

    最后权衡了一下,还是选择了方法(二)来解决此问题。

    原因是:

    (1)我希望将自动重启机制也加进来。由于vlc本身并不是很稳定,在运行时可能会崩溃;而 我们的转发服务不能停。

    因此,如果主进程发现某一路子进程退出了,立即检查是否需要重启(有多种退出原因,可能是主动停止的),如果需要,就查找是哪一路节目,然后立即fork()出一个子进程进行转发。

    (2)至于多线程加锁的问题, 后来确认了一下,实际上并不存在此问题。因为在父进程监测线程中并不需要对子进程列表进行写操作,只需要查询即可.

     

     

     

     

  • 相关阅读:
    log4j配置详解
    elasticsearch6.0版本安装head插件
    JAVA笔记-如何将百万级数据高效的导出到Excel表单
    抽象方法为什么不能被private与static修饰
    vue利用promise实现连续弹框
    vue代码片段
    h5元素高度超出屏幕但不滚动
    css3动画
    vue 引入静态图片404
    ios windows.open()不能打开
  • 原文地址:https://www.cnblogs.com/chutianyao/p/2321553.html
Copyright © 2020-2023  润新知