我有一个启动工作进程的程序,等待它完成(侦听SIGCHLD
信号),然后启动另一个工作进程。在我的工作进程中,我启动了一个调用另一个程序的QProcess
。在我的测试用例中,我调用touch
- 标准的Linux命令。
我使用fork()
和execv()
来启动工作进程。
问题是QProcess
仅在第一个工作进程中成功完成。生成新的工作进程后,QProcess
从未说明它已完成。 touch
命令本身始终正常工作。但是在除了第一个工作流程之外的所有工作流程中,它最终变成了僵尸。
这是一个最小的测试程序:
#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";
}
}
答案 0 :(得分:1)
你永远不应该从信号处理程序中调用glibc。处理程序是异步调用的,这意味着它们可以中断系统调用。这些电话可能不是可重入的。要了解有关此内容的更多信息,请查看以下页面:
http://www.gnu.org/software/libc/manual/html_node/Nonreentrancy.html