1

I am using QProcess for the first time, and while experimenting I noticed that readyRead is signaled before started.

I tried running /usr/bin/echo foobar with QProcess, and attached two functions to readyRead() and started() signals, and I get output in this order:

  1. process start with start() method
  2. dataReady() signal
  3. started() signal

Now, I find a bit strange that started() is after dataReady(), because usually a process become in the running state before it can actually produce data, but I can not find anything about this order in the documentation, and maybe this is perfectly logical, but... Can someone explain me why this happens?

EDIT: I add here a code that behaves like I said. I am using Qt 4.8.4 64 bit.

/*****************************************************************************/
// multiproc.hh
#ifndef MULTIPROC_HH
#define MULTIPROC_HH

#include <QObject>
#include <QtCore>
#include <iostream>
#include "node.hh"

class MultiProc: public QObject {
    Q_OBJECT
public:
    MultiProc(QObject *parent = 0):
        QObject(parent) {
        std::cout << "MultiProc\n";

        QList<QStringList> args;
        args << (QStringList() << "/usr/bin/echo" << "Proc 0 running");
        args << (QStringList() << "/usr/bin/echo" << "Proc 1 running");
        args << (QStringList() << "/usr/bin/cat");
        args << (QStringList() << "/usr/bin/cat");
        args << (QStringList() << "/usr/bin/tee" << "/etc/hostname");

        for (int i = 0; i < args.size(); ++i)
            _nodes << new Node(this, i, args[i]);
    }
signals:
    void finished();
public slots:
    void run() {
        std::cout << "Starting all nodes :)\n";
        foreach (Node *n, _nodes)
            n->start();
    }
private:
    QList<Node *> _nodes;
};

#endif // MULTIPROC_HH

/*****************************************************************************/
// node.hh
#ifndef NODE_HH
#define NODE_HH

#include <QtCore>
#include <iostream>

class Node: public QObject {
    Q_OBJECT
public:
    Node(QObject *parent, int id, const QStringList &args):
        QObject(parent),
        _id(id),
        _proc(new QProcess(this)),
        _args(args) {
        std::cout << "Node " << _id << " created with command "
                  << args.join(" ").toStdString() << "\n";
        connect(_proc, SIGNAL(started()), this, SLOT(started()));
        connect(_proc, SIGNAL(finished(int)), this, SLOT(finished()));
        connect(_proc, SIGNAL(readyRead()), this, SLOT(readyRead()));
        connect(_proc, SIGNAL(error(QProcess::ProcessError)),
                this, SLOT(error(QProcess::ProcessError)));
    }
    void start() {
        if (_proc->state() == QProcess::NotRunning) {
            std::cout << "Starting process on node: " << _id << "\n";
            _proc->start(_args.at(0), _args.mid(1));
        }
    }
public slots:
    void started() { std::cout << "Node " << _id << " started\n"; }
    void finished() { std::cout << "Node " << _id << " finished\n"; }
    void readyRead() { std::cout << "Node " << _id << " readyRead\n"; }
    void error(QProcess::ProcessError err) {
        std::cout << "Node " << _id << " Error: " << err << "\n";
        QCoreApplication::exit(1);
    }
private:
    int _id;
    QProcess *_proc;
    QStringList _args;
};

#endif // NODE_HH

/*****************************************************************************/
// main.cpp
#include <QCoreApplication>
#include "multiproc.hh"

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

    MultiProc *p = new MultiProc(&a);
    QObject::connect(p, SIGNAL(finished()), &a, SLOT(quit()));
    QTimer::singleShot(0, p, SLOT(run()));
    return a.exec();
}

And here a piece of output:

Node 0 readyRead
Node 2 started
Node 0 started
Node 0 finished
Node 1 started
Node 1 readyRead
Node 4 started
Node 1 finished
Node 3 started
4

1 回答 1

2

我可以通过首先启动进程然后连接信号来使用 Linux 和 Qt 5.0.1 重现这一点:

process.start("echo foo", QIODevice::ReadWrite);

connect(&process, SIGNAL(started()), this, SLOT(started()));
connect(&process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyRead()));

但是,如果我先连接信号然后启动进程,则started()首先调用插槽作为例外。

您发现的功能可能被视为错误,您可能希望将其报告给Qt 错误跟踪器

编辑:

我能够用您的代码重现问题。start()我还可以通过对 Node 的功能进行一些小改动来修复它。调用后start()调用waitForStarted()才继续。请注意,仅在进程状态为时等待QProcess::Starting可以避免尝试启动不存在的程序时出现问题。在那种情况下,该过程将永远不会开始。当然,也可以通过为waitForStarted函数使用除 -1 之外的其他超时来避免这种情况。

void start()
{
    if (_proc->state() == QProcess::NotRunning) 
    {
        std::cout << "Starting process on node: " << _id << "\n";
        _proc->start(_args.at(0), _args.mid(1));
        if (_proc->state() == QProcess::Starting)
            _proc->waitForStarted(-1);
    }
}
于 2013-04-28T20:22:37.663 回答