Qt QThread 爬坑之旅(一)

来源:互联网 发布:vegas13是电脑软件 编辑:程序博客网 时间:2024/06/15 01:58

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_OBJECTpublic:    explicit MainWindow(QWidget *parent = 0);    ~MainWindow();signals:    void doWorkSignal();private:    Ui::MainWindow *ui;    QThread m_thread;    Worker m_worker;};#endif // MAINWINDOW_H

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();}

worker.h

#ifndef WORKER_H#define WORKER_H#include <QObject>#include <QThread>#include <QNetworkAccessManager>class WorkerA: public QObject{    Q_OBJECTpublic:    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_OBJECTpublic:    explicit Worker(QObject *parent = 0);    ~Worker();signals:public slots:    void doWork();private:    WorkerA *m_workerA;};#endif // WORKER_H

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;}

程序运行输出:

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)

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

m_net2 = new QNetworkAccessManager(this);

查看官方文档可以知道,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). new时不传递this指针

m_net2 = new QNetworkAccessManager;

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

m_net1 = new QNetworkAccessManager(this);m_net2 = new QNetworkAccessManager(this);

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

总结

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

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

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

0 0