zoukankan      html  css  js  c++  java
  • QThread 爬坑之旅(三种办法解决QObject: Cannot create children for a parent that is in a different thread)

    Cannot create children for a parent that is in a different thread.

    在Qt的官方文档,大家知道有两种方式使用 QThread。

    • You can use worker objects by moving them to the thread using QObject::moveToThread().
    • Another way to make code run in a separate thread, is to subclass QThread and reimplement run().

    在使用MoveToThread这种方式时,经常会遇到下面类似的问题:

    • QObject: Cannot create children for a parent that is in a different thread.

    出现这样的问题根本原因就是,调用MoveToThread 之后,在 Worker的槽函数中Worker的私有成员中又进行了new操作,并且将this指针传给了构造函数。看下实例:

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QThread>
    #include <QMainWindow>
    
    #include "worker.h"
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    signals:
        void doWorkSignal();
    
    private:
        Ui::MainWindow *ui;
    
        QThread m_thread;
    
        Worker m_worker;
    };
    
    #endif // MAINWINDOW_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        m_worker.moveToThread(&m_thread);
    
        connect(this, SIGNAL(doWorkSignal()),
                &m_worker, SLOT(doWork()));
    
        m_thread.start();
    
        emit doWorkSignal();
    
        qDebug() << "MainWin thread: " << QThread::currentThread();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    
        m_thread.exit();
        m_thread.wait();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    worker.h

    #ifndef WORKER_H
    #define WORKER_H
    
    #include <QObject>
    #include <QThread>
    #include <QNetworkAccessManager>
    
    class WorkerA: public QObject
    {
        Q_OBJECT
    public:
        inline explicit WorkerA(QObject *parent = 0)
        {
            m_net1 = new QNetworkAccessManager(this);
    
            qDebug() << "Create WorkerA thread: " << QThread::currentThread();
        }
    
        inline void doWorkA()
        {
            m_net2 = new QNetworkAccessManager(this);
    
            qDebug() << "DoWorkA thread: " << QThread::currentThread();
            qDebug() << "Net1 Parent: " << m_net1->parent();
            qDebug() << "Net2 Parent: " << m_net2->parent();;
        }
    
        inline ~WorkerA()
        {
            delete m_net1;
            delete m_net2;
        }
    
    
    private:
        QNetworkAccessManager *m_net1;
        QNetworkAccessManager *m_net2;
    };
    
    class Worker : public QObject
    {
        Q_OBJECT
    public:
        explicit Worker(QObject *parent = 0);
        ~Worker();
    
    signals:
    
    public slots:
        void doWork();
    
    private:
        WorkerA *m_workerA;
    
    };
    
    #endif // WORKER_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    worker.cpp

    #include <QDebug>
    
    #include "worker.h"
    
    Worker::Worker(QObject *parent) :
        QObject(parent)
    {
        m_workerA = new WorkerA(this);
    
        qDebug() << "Create Worker thread: " << QThread::currentThread();
    }
    
    void Worker::doWork()
    {  
        qDebug() << "doWork thread: " << QThread::currentThread();
    
        m_workerA->doWorkA();
    }
    
    Worker::~Worker()
    {
        //delete m_workerTimer;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    程序运行输出:

    Create WorkerA thread:  QThread(0x4482e8)
    Create Worker thread:  QThread(0x4482e8)
    MainWin thread:  QThread(0x4482e8)
    doWork thread:  QThread(0x28fe1c)
    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is WorkerA(0x4558a8), parent's thread is QThread(0x4482e8), current thread is QThread(0x28fe1c)
    DoWorkA thread:  QThread(0x28fe1c)
    Net1 Parent:  WorkerA(0x4558a8)
    Net2 Parent:  QObject(0x0)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在本案例中,Worker在槽函数中调用私有成员WorkerA的doWorkA(),doWorkA()中

    m_net2 = new QNetworkAccessManager(this);
    • 1

    查看官方文档可以知道,doWork槽函数会在另外一个线程被执行。这里 
    有new操作,而且传递了this指针,而且我们也可以从打印信息可知道此时this指针和doWorkA()不在同一线程,所以会报出错误:

    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is WorkerA(0x4558a8), parent's thread is QThread(0x4482e8), current thread is QThread(0x28fe1c)
    • 1
    • 2

    解决办法是: 
    (1). new时不传递this指针

    m_net2 = new QNetworkAccessManager;
    • 1

    (2). 将new操作放在WorkerA的构造函数中

    m_net1 = new QNetworkAccessManager(this);
    m_net2 = new QNetworkAccessManager(this);
    
    • 1
    • 2
    • 3

    (3).使用信号与槽的方法调用doWorkA()

    总结

    QObject: Cannot create children for a parent that is in a different thread.
    • 1

    这样的错误,多是由于在槽函数中多层嵌套时new操作出的问题,建议大家尽量避免在槽函数中进行new操作。

    测试代码: 
    https://github.com/RobinsonSir/QThreadTest1

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zbc415766331/article/details/52462118
     
    其实还是第四种做法,就是把WorkerA再次moveToThread一下,毕竟它是在构造函数里创建的,而那时候Worker所在的线程还是主线程。
  • 相关阅读:
    Leetcode 191.位1的个数 By Python
    反向传播的推导
    Leetcode 268.缺失数字 By Python
    Leetcode 326.3的幂 By Python
    Leetcode 28.实现strStr() By Python
    Leetcode 7.反转整数 By Python
    Leetcode 125.验证回文串 By Python
    Leetcode 1.两数之和 By Python
    Hdoj 1008.Elevator 题解
    TZOJ 车辆拥挤相互往里走
  • 原文地址:https://www.cnblogs.com/findumars/p/9361993.html
Copyright © 2011-2022 走看看