Linux下QProcess不产生finished信号、waitforfinished阻塞超时【defunct进程】

项目场景:

  • 2022-04-28

    涉及Linux下的多进程编程,比较让人绕晕。
    初步以为,是由于在子进程中,又创建了子进程,导致的最后创建的子进程异常。

  • 2022-04-29

    今天早早的到了单位,任然放不下昨天的问题,于是乎一坐下,我就翻起了经典《UNIX高级环境编程》。
    一小时之后,似乎有点眉目,便更新了此文档。


问题描述以及分析过程:

  • 2022-04-28
  1. 使用fork函数,创建子进程A;
  2. A主要 调用execvp函数拉起QT主程序B;
  3. 主程序B中调用QProcess::start函数调用进程C(ffmpeg的命令);
  4. B中connect进程C的finished信号,或者waitforfinished均失败;
异常有:1. finished信号不触发;
		2. ffmpeg转码明明结束了,进程却不推出;
		3. 调用waiforfinished一直阻塞,直到30秒超时;
  • 2022-04-29

看过书后,再分析这个问题,似乎有底气了。 介绍一下我的主题部分:
broadcast_daemon: 守护进程,负责fork子进程并且监听子进程状态
broadcast_media_ser: 主服务程序
ffmpeg: 负责转码的进程

  1. 查看一下这个子进程的ID,使用指令分析:“ps -ef|grep ffmpeg”,结果如下:
    在这里插入图片描述
  2. 可以看到,该子进程的pid=2992,它的父进程ppid=2983;查看2983进程,正式我守护进程拉起的QT主程序;
    在这里插入图片描述
  3. 然看到ffmpeg的进程此时已是“defunct”进程,即“僵尸进程”了;
  4. 按惯例贴出我的代码:
    在这里插入图片描述
    5.考虑僵尸进程到底出现的原因

defunct(僵尸进程):

摘自网络结合个人总结:

  1. 什么是僵尸进程?

僵尸进程是一个早已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。

  1. 僵尸进程产生的原因是什么?(归其原因:需要wait\waitpid)

在 Linux 系统中,一个子进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程;
如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程;
每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,看看有没有哪个 进程是刚刚结束的这个进程的子进程,如果是的话,就由Init进程来接管他,成为他的父进程,从而保证每个进程都会有一个父进程。
而Init进程会自动 wait其子进程,因此被Init接管的所有进程都不会变成僵尸进程。

  1. 僵尸进程的危害?

进程号会一直被占用,但是系统的进程表容量是有限的,所能使用的进程号也是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程。
所以,defunct进程不仅占用系统的内存资源,影响系统的性能,而且如果其数目太多,还会导致系统瘫痪。而且,由于调度程序无法选中Defunct


QProcess的实现:

主要关注其创建的原来、以及waitforfinished函数、finished信号等产生的原理:
QT的通信可分为QT内部通信和外部通信两大类;

  1. QProcess进程的三个接口实现:

QProcess::execute():
此函数是以阻塞的方式打开外部程序,只有外部程序执行完成后,主程序才会继续执行。外部程序的标准输出、标准错误都是重定向到主程序的标准输出和标准错误的。
QProcess::start(): 此函数是以子进程的 方式打开外部程序的,外部进程与主程序互不干扰,但外部进程的父进程就是主程序。
QProcess::startDetached():
此函数是以分离的方式打开外部程序的,外部程序与主程序互不干扰,外部进程的父进程是系统的init进程。

  1. QProcess的机制分析:

启动QProcess的主程序为父进程,QProcess的调用为子进程;他们之间的通信机制如同常用的父子通信机制。而最主要的QProcess实现父子进程间的通信过程是运用Linux系统的无名管道来实现的,所以它会有I/O设备的write、read函数等操作。

理论原因:

综合上面的分析,现在得出以下结论:

  1. 使用QProcess的start函数之后,QT主程序作为父进程,没有调用wait,导致子进程变成了僵尸进程;

尝试修改一:

  1. 发现一个问题:代码查看我的上一篇:
    链接在此:分享一份Linux守护进程代码
    在这里插入图片描述
  2. 我发现以下问题:

1.在圈出来的函数中,启动的程序,它是可以处理QProcess的信号的,并且我们的ffmpeg也不会变成僵尸进程;
2. 在initWatchDog看门狗程序中,启动的进程则无法处理,这就很奇怪;
3. 于是乎开始分析守护进程的代码异常;

  1. 第一次启动时,waitdog正在挂起pause;此时一切是正常的。
    在这里插入图片描述
    在这里插入图片描述

  2. 当我尝试kill掉子进程broad_media_ser时,情况如下:

先是接收到了17;(Child status has changed),发现信号是9,这个时候就开始调用fork,当pid==0表示子进程空间,

在这里插入图片描述

执行下面代码;

在这里插入图片描述

  1. 通常来说,pid==0表示子进程空间,pid!=0表示父进程空间;真相大白了,父进程空间中并没有wait其结束;修改成如下代码:
    在这里插入图片描述

  2. 当重新试一下之后:失败了!!!

发现问题依旧!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!纳尼???????

第一次痛定思痛:

  1. 我发现在守护进程以及QT主服务之间,各个流程都是OK的,没有问题;
  2. 我发现,问题的集中点在于QT主服务已经是子进程,它作为父进程再创建子进程ffmpeg,ffmpeg究竟应该被谁wait???

尝试修改二:

  1. 我用以下的代码测试了一下,发现是OK的
    在这里插入图片描述
  2. 说明,QT主程序作为子进程,被频繁创建肯定没有问题;QPRocess类也是可以被支持的。
  3. 最后我把守护进程的代码改成了下面这样,用最简单的方式实现了功能:
int main()
{
    int pid = 0;
    int status = 0;
    param = new char[100];
    memset(param,0,100);
    pcmd = new char[1024];
    memset(pcmd,0,1024);

    strcpy(param,"-log");
    get_process_path(pcmd);
    strcat(pcmd,pservername);


    while(true)
    {
        pid = fork();
        if(pid == 0)
        {
            childProcessFunc();
        }if(pid != 0)
        {
            wait(&status);
            if (WIFSIGNALED(status))
            {
                int signalNum = WTERMSIG(status);
                printf("Child process was killed by signal num: %d\n", signalNum);
            }
            // 检测是否生成了core文件
            if (WCOREDUMP(status))
            {
                printf("Child process core dump file generated\n");
            }
            // 等待3秒钟重新启动子进程
            sleep(3);
        }
    }
    delete[] pcmd;
    delete[] param;
    return 0;
}

第二次修改能满足要求:

原因应该还是代码运用错误。

使用startdetched分离进程:

分离后,可以通过读取进程表,来进行判断,这也是一种方法。
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShaYQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值