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所在的线程还是主线程。

猜你喜欢

转载自www.cnblogs.com/findumars/p/9361993.html