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操作。