QProcess в потоке работает, но с двумя типами ошибок вывода - PullRequest
0 голосов
/ 13 февраля 2020

Я изучаю многопоточность QT. Со следующим кодом все работает нормально, но есть две ошибки типа. Код слишком прост, чтобы выяснить, что происходит не так.

CmdController (поток контроллера) -> CMD (тестовый поток Ping) -> QProcess ( извините "ping")

main. c

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

        QCoreApplication a(argc, argv);

        // create Test object, and then execute “ping” cmd under windows
        CmdController Test;
        Test.process();

        return a.exec();
    }

CmdController.h

    // deal with "ping" command
    class Cmd : public QObject
    {
        Q_OBJECT
    public:
        explicit Cmd();

    private:
        QProcess CmdExe;

    public slots:
        void process();
        void readFromStdOut();
    };


    // Controller class
    class CmdController : public QObject
    {
        Q_OBJECT
    public:
        explicit CmdController();
        ~CmdController();

    signals:
        void process();

    private:
        QThread mThread;
        Cmd mCmd;
    };

CmdController. c

    Cmd::Cmd()
    {
        connect(&CmdExe, SIGNAL(readyReadStandardOutput()), this, SLOT(readFromStdOut()));
    }

    void Cmd::process()
    {
        CmdExe.start("ping", {"www.baidu.com"});
    }


    void Cmd::readFromStdOut()
    {
        QByteArray resault = CmdExe.readAllStandardOutput();
        qDebug() << QTextCodec::codecForName("GBK")->toUnicode(resault);
    }

    CmdController::CmdController()
    {
        mCmd.moveToThread(&mThread);
        connect(this, &CmdController::process, &mCmd, &Cmd::process);

        mThread.start();
    }

    CmdController::~CmdController()
    {
        mThread.exit();
        mThread.wait();
    }

Вывод:

    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QProcess(0x6ffdf0), parent's thread is QThread(0x1f6510), current thread is QThread(0x6ffdd0)
    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QProcess(0x6ffdf0), parent's thread is QThread(0x1f6510), current thread is QThread(0x6ffdd0)
    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QProcess(0x6ffdf0), parent's thread is QThread(0x1f6510), current thread is QThread(0x6ffdd0)
    "\r\n正在 Ping www.a.shifen.com [180.101.49.42] 具有 32 字节的数据:\r\n"
    "来自 180.101.49.42 的回复: 字节=32 时间=31ms TTL=53\r\n"
    "来自 180.101.49.42 的回复: 字节=32 时间=31ms TTL=53\r\n"
    "来自 180.101.49.42 的回复: 字节=32 时间=30ms TTL=53\r\n"
    "来自 180.101.49.42 的回复: 字节=32 时间=30ms TTL=53\r\n\r\n180.101.49.42 的 Ping 统计信息:\r\n    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),\r\n往返行程的估计时间(以毫秒为单位):\r\n    最短 = 30ms,最长 = 31ms,平均 = 30ms\r\n"
    QObject::connect: Cannot queue arguments of type 'HANDLE'
    (Make sure 'HANDLE' is registered using qRegisterMetaType().)

Ошибка 1-ая: ошибка вывода 1-6 строк, показывает, что создание дочернего объекта происходит три раза. Пинг тест в порядке. Итак, кто вызвал ошибку?

QThread (0x6ffdd0) является Cmd-объектом, QThread (0x1f6510) является CmdController-объектом, QProcess (0x6ffdf0) явно является QProcess-объектом, означает ли это QProcess, попытайтесь создать что-то?

Ошибка 2ed: последние две строки. googled, не могу найти 'HANDLE', что это такое.

Если, если удалить многопоточность из CmdController (поток контроллера) -> CMD (тестовый поток Ping) -> QProcess (excute "ping") в CmdController ( Поток контроллера) -> QProcess (извините "ping") ошибки не будет, все работает отлично.

Я в замешательстве.

Спасибо.

1 Ответ

0 голосов
/ 13 февраля 2020

Чтобы понять проблему, нужно сначала прояснить, что QObject должен выполняться только в потоке, которому он принадлежит, если выполняется другой поток, то Qt не гарантирует, что он работает, и именно это произошло в этом case.

Давайте проанализируем, к какому потоку принадлежит каждый QObject, по умолчанию QObject принадлежит потоку, в котором он был создан, или потоку его отца, поэтому при создании объекта «Test» он принадлежит основному потоку. объект «mCmd» в начале принадлежит основному потоку, а затем вы перемещаете его в «mThread», «CmdExe» принадлежит потоку, в котором он был создан, то есть к основному потоку, но процессу «Cmd» метод выполняется во вторичном потоке, но «CmdExe» выполняется в главном потоке, вызывая проблему.

Решение состоит в том, чтобы сделать «CmdExe» сыном «Cmd», чтобы оба принадлежали одному и тому же потоку и не создает проблем.

// ...
class Cmd : public QObject
{
    Q_OBJECT
public:
    explicit Cmd(QObject *parent=nullptr);

private:
    <b>QProcess *CmdExe;</b>
public slots:
    void process();
    void readFromStdOut();
};
// ...

// ...
Cmd::Cmd(QObject *parent):QObject(parent), <b>CmdExe(new QProcess(this))</b>
{
    connect(<b>CmdExe</b>, &QProcess::readyReadStandardOutput, this, &Cmd::readFromStdOut);
}

void Cmd::process()
{
    <b>CmdExe->start("ping", {"www.baidu.com"});</b>
}
// ...
...