QProcess readyRead在开始之前

时间:2013-04-28 13:07:33

标签: qt qt4 qprocess

我第一次使用QProcess,在进行实验时,我注意到readyRead之前已发出started信号。

我尝试使用/usr/bin/echo foobar运行QProcess,并将两个函数附加到readyRead()started()信号,然后按此顺序输出:

  1. 进程以start()方法开始
  2. dataReady()signal
  3. started()signal
  4. 现在,我发现started()dataReady()之后有点奇怪,因为通常一个进程在之前就已经处于运行状态它实际上可以生成数据了,但我可以在文档中没有找到关于此顺序的任何内容,也许这是完全符合逻辑的,但是......有人可以解释为什么会发生这种情况吗?

    编辑: 我在这里添加一个行为就像我说的那样。我正在使用Qt 4.8.4 64位。

    /*****************************************************************************/
    // 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();
    }
    

    这是一个输出:

    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
    

1 个答案:

答案 0 :(得分: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 bug tracker

修改

我能够使用您的代码重现问题。我还可以通过对Node的start()函数进行一些小改动来修复它。在继续之前致电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);
    }
}