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所在的线程还是主线程。
  • 相关阅读:
    C# WinForm程序中强制退出程序以及启动程序
    WinForm程序中对关闭按钮的操作
    DataTable转换为List
    json日期转换
    ajax局部刷新
    程序暂停或延迟几秒再次运行
    分页显示的制作流程
    Django 项目基础操作总结
    Django初识
    Mysql有关分页的操作
  • 原文地址:https://www.cnblogs.com/findumars/p/9361993.html
Copyright © 2011-2022 走看看