加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – fork()和execv()之后的QProcess问题

发布时间:2020-12-16 07:09:08 所属栏目:百科 来源:网络整理
导读:我有一个程序,它启动一个工作进程,等待它完成(监听SIGCHLD信号),然后启动另一个工作进程.在我的工作进程中,我启动了一个调用另一个程序的QProcess.在我的测试用例中,我称之为touch – 标准的 Linux命令. 我使用fork()和execv()来启动工作进程. 问题是QProces
我有一个程序,它启动一个工作进程,等待它完成(监听SIGCHLD信号),然后启动另一个工作进程.在我的工作进程中,我启动了一个调用另一个程序的QProcess.在我的测试用例中,我称之为touch – 标准的 Linux命令.

我使用fork()和execv()来启动工作进程.

问题是QProcess仅在第一个工作进程中成功完成.生成新的工作进程后,QProcess永远不会说它已完成.触摸命令本身一直都很好.但是在除了第一个工作流程之外的所有工作流程中,它最终变成了僵尸.

这是一个最小的测试程序:

#include <QCoreApplication>
#include <QProcess>
#include <QDebug>

#include <signal.h>
#include <wait.h>

void spawnWorkerProcess();
void launchQProcess();
void catchSigChild(int i);
void execChild();

int main(int argc,char *argv[])
{
    QCoreApplication app(argc,argv);

    if (argc > 1) // worker process
    {
        launchQProcess();
    }
    else // main process
    {
        if (signal(SIGCHLD,catchSigChild) == SIG_ERR)
        {
            qFatal("could not attach to SIGCHLD");
        }

        spawnWorkerProcess();

        return app.exec();
    }
}

void spawnWorkerProcess()
{
    pid_t pid = fork();
    if (pid == -1)
    {
        qCritical() << "FORK ERROR";
        exit(1);
    }
    else if (pid == 0)
    {
        /* the child process */
        execChild();
        exit(1);
    }
    else
    {
        qWarning() << "FORK OK";
    }
}


void
execChild()
{
    unsigned i = 0;
    const char **argv = new const char *[3];

    QByteArray ba = qApp->applicationFilePath().toLocal8Bit();
    argv[i++] = ba.data();
    argv[i++] = "worker";
    argv[i++] = 0;

    qWarning() << "execv ..."  << argv;
    execv(argv[0],const_cast<char *const *>(argv));
    qWarning() << "execv OK";

    delete[] argv;
}

void catchSigChild(int i)
{
    qCritical() << Q_FUNC_INFO << i;

    pid_t cpid;
    int stat;

    while ((cpid = waitpid(0,&stat,WNOHANG)) > 0)
    {
        static int counter = 0;

        counter++;

        if (counter < 5)
        {
            qDebug() << "SPAWN:" << counter;
            spawnWorkerProcess();
        }
        else
        {
            qCritical() << "RESPAWN LIMIT REACHED! Bye-bye!";
            exit(0);
        }
    }
}
void
launchQProcess()
{
    QProcess pr;

    qWarning() << "start QProcess " << qApp->applicationPid();
    pr.start(QString("touch /tmp/test/%1").arg(qApp->applicationPid()),0);

    if (! pr.waitForFinished(3000))
    {
        qWarning() << "QProcess FAIL" << qApp->applicationPid() << pr.state() << "n";

        delete (int*) 1; // we don't want to wait for QProcess timeout,so doing crash
    }
    else
    {
        qWarning() << "QProcess OK" << qApp->applicationPid() << pr.state() << "n";
    }
}

解决方法

你永远不应该在信号处理程序中调用glibc.处理程序是异步调用的,这意味着它们可以中断系统调用.这些电话可能不是可重入的.要了解有关此内容的更多信息,请查看以下页面:

http://www.gnu.org/software/libc/manual/html_node/Nonreentrancy.html

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读