QProcess在没有waitForFinished()时不发出信号

时间:2016-08-19 10:14:38

标签: c++ qt

在下面的代码中,省略waitForFinished()会使QProcess停止发出信号。这有什么问题呢?这是Qt Bug吗? (5.7)。请注意,此代码与QtConcurrent run并行运行。但这应该不会改变任何东西,不是吗? Afaik在其他线程中发送信号很好,但它们会排队等。

QProcess *process = new QProcess;
process->setReadChannel(QProcess::StandardOutput);

connect(process, &QProcess::readyReadStandardOutput, [](){
    qDebug()<< "readyReadStandardOutput";
});

connect(process, &QProcess::stateChanged, [](QProcess::ProcessState state){
    qDebug()<< "stateChanged"<< state;
});

connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
    [=](){
    qDebug()<< "finsished";
});

connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
    [this, process](int exitCode, QProcess::ExitStatus exitStatus){
    qDebug()<< "finsished";
    if (exitStatus == QProcess::NormalExit && exitCode == 0){
        while (process->canReadLine()) {
           QString line = QString::fromLocal8Bit(process->readLine());
           QRegularExpression regex("\"(.*)\" {(.*)}");
           QRegularExpressionMatch match = regex.match(line);
           names_.push_back(match.captured(1));
           uuids_.push_back(match.captured(2));
        }
    }
    process->deleteLater();
});
process->start("VBoxManage",  {"list", "vms"});
process->waitForFinished(); // This line changes everything
qDebug()<< "leftWaitForFinished";

1 个答案:

答案 0 :(得分:4)

您没有在QProcess实例所在的线程中运行事件循环。没有事件循环的线程中的任何QObject只是部分功能 - 定时器不会运行,排队的调用将不会被传递等等。所以你不能这样做。将QObjectQtConcurrent::run一起使用需要小心。

至少,只要进程存在,就应该有一个临时的事件循环 - 在这种情况下,你应该按值保持QProcess,因为deleteLater之后不会执行QProcess process; ... QEventLoop loop; connect(process, &QProcess::finished, &loop, &QEventLoop::quit); loop.exec(); 事件循环已退出。

QThread

否则,你需要将进程保持在一个更持久的线程中,并保持该线程句柄(// This can be run from a lambda that runs in an arbitrary thread auto thread = new QThread; auto process = new QProcess; ... connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), [this, process](int exitCode, QProcess::ExitStatus exitStatus){ ... process->deleteLater(); process->thread()->quit(); }); process->start("VBoxManage", {"list", "vms"}); process->moveToThread(thread); // Move the thread **handle** to the main thread thread->moveToThread(qApp->thread()); connect(thread, &QThread::finished, thread, &QObject::deleteLater); thread->start(); 只是一个句柄!)在一个具有事件循环的线程中,该事件循环可以在完成后处理它

QProcess
唉,这是非常愚蠢的,因为你正在创建临时线程,这是昂贵和浪费。您应该有一个额外的工作线程,您可以在其中处理所有低开销工作,例如QProcess交互。该线程应始终运行,您可以将所有{{1}}和类似的对象实例从并发lambda等移动到它。