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。html

  • 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這種方式時,常常會遇到下面相似的問題:c++

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

出現這樣的問題根本緣由就是,調用MoveToThread 以後,在 Worker的槽函數中Worker的私有成員中又進行了new操做,而且將this指針傳給了構造函數。看下實例:git

mainwindow.hgithub

#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.cppmarkdown

#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

程序運行輸出:ui

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()中this

m_net2 = new QNetworkAccessManager(this);
  • 1

查看官方文檔能夠知道,doWork槽函數會在另一個線程被執行。這裏 
有new操做,並且傳遞了this指針,並且咱們也能夠從打印信息可知道此時this指針和doWorkA()不在同一線程,因此會報出錯誤:spa

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所在的線程仍是主線程。
相關文章
相關標籤/搜索