c++ - 当不是 waitForFinished() 时,QProcess 不发出信号

标签 c++ qt

在以下代码中,省略 waitForFinished() 会使 QProcess 停止发出信号。它到底有什么问题?这是Qt Bug吗? (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";

最佳答案

您没有在 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 和类似的对象实例从并发 lambda 等移动到它。

关于c++ - 当不是 waitForFinished() 时,QProcess 不发出信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39036458/

相关文章:

c++ - 将 C 字符串转换为 int 数组

c++ - 链接图的顶点

c++ - 扁平化为 1D 数组的 2D 和 3D 数组的等效迭代?

javascript - 将元素添加到带有动画的转发器

c++ - QTableView拖放行无法正常工作

c++ - 将 std::cout 添加到全局运算符新掩码 SIGSEGV

c++ - 从一个新的位置访问一个静态 constexpr 成员是一个常量表达式吗?

c++ - 如何设置QTreeWidget表头颜色和隐藏分界线?

c++ - 如何在Qt中完成下拉单词建议?

Qt:以编程方式定义 Tab Order