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

Man*_*d3r 3 c++ qt

在下面的代码中,省略waitForFinished()使 QProcess 停止发出它的信号。它到底有什么问题?这是一个Qt错误吗?(5.7)。请注意,此代码与 QtConcurrent 并行运行。但这不应该改变任何事情,不是吗?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";
Run Code Online (Sandbox Code Playgroud)

Rei*_*ica 7

您没有在QProcess实例所在的线程中运行事件循环。任何QObject在没有事件循环线程只是部分功能-定时器将不会运行,排队的呼叫将无法送达,等于是你不能做到这一点。使用QObjects withQtConcurrent::run需要小心。

至少,只要进程存在,您就应该有一个临时事件循环 - 在这种情况下,您应该QProcess按值持有,因为deleteLater在事件循环退出后不会执行。

QProcess process;
...
QEventLoop loop;
connect(process, &QProcess::finished, &loop, &QEventLoop::quit);
loop.exec();
Run Code Online (Sandbox Code Playgroud)

Otherwise, you need to keep the process in a more durable thread, and keep that thread handle (QThread is but a handle!) in a thread that has an event loop that can dispose of it when it's done.

// 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();
Run Code Online (Sandbox Code Playgroud)

Alas, this is very silly since you're creating temporary threads and that's expensive and wasteful. You should have one additional worker thread where you take care of all low-overhead work such as QProcess interaction. That thread should always be running, and you can move all QProcess and similar object instances to it, from concurrent lambdas etc.

  • 我已经确切地说明了它为什么不起作用:这是因为对于像 QProcess 这样的 QObject 要起作用,它运行的线程必须运行一个事件循环!它与 lambdas 或类似的东西**无关**。调用 `run` 的对象无关紧要:lambda 在没有事件循环的工作线程中运行。 (2认同)