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操作。
QThread 爬坑之旅(三种办法解决QObject: Cannot create children for a parent that is in a different thread)的更多相关文章
- java——多线程的实现方式、三种办法解决线程赛跑、多线程数据同步(synchronized)、死锁
		
多线程的实现方式:demo1.demo2 demo1:继承Thread类,重写run()方法 package thread_test; public class ThreadDemo1 extends ...
 - 记一次项目使用webuploader爬坑之旅
		
因前端页面开发使用的为VUE开发,又要支持IE9,遂只有基于webuploader封装一个上传组件.地址:https://github.com/z719725611/vue-upload-web ...
 - PHP修改memory_limit的三种办法
		
PHP修改memory_limit的三种办法 2010-06-11 10:57:11 分类: 可能是分词程序的问题.只要搜索的字段达到十个汉字以上,就会出现诸如以下的错误 Fatal error: ...
 - 三种方法解决android帮助文档打开慢
		
三种方法解决android帮助文档打开慢 经查是因为本地文档中的网页有如下两段js代码会联网加载信息,将其注释掉后就好了 <link rel="stylesheet" h ...
 - Oracle用户解锁的三种办法及默认的用户与密码
		
ORA-28000: the account is locked-的解决办法 2009-11-11 18:51 ORA-28000: the account is locked 第1步:使用PL/SQ ...
 - 解决Viewpager满屏不能自适应填充内容的三种办法
		
由于排版问题,本人博客园同名博文地址为:http://www.cnblogs.com/bill-technology/articles/3143667.html 很多Android开发者在使用View ...
 - WEB项目会话集群的三种办法
		
web集群时session同步的3种方法 在做了web集群后,你肯定会首先考虑session同步问题,因为通过负载均衡后,同一个IP访问同一个页面会被分配到不同的服务器上, 如果session不同步的 ...
 - 部署vc2008开发的程序(三种办法,但是我觉得这种办法最不好)
		
如果你编译了一个VC2008的默认的CRT/MFC的应用程序,如果目标部署电脑上没有安装相应的VC2008的动态库,当运行你的程序的时 个,会出现如下错误信息. 这是因为程序使用了基于VC2008 ...
 - Android 再按一次退出程序三种办法
		
在Xamarin android中双击返回键退出程序的第一种做法 思路就是当用户按下返回键的时间超过两秒就退出,根据Keycode.Back判断用户按下的是返回键,重写这个OnKeyDown Date ...
 
随机推荐
- VUE项目axios请求头更改Content-Type
			
const httpServer = (opts, data) => { const token = localStorage.getItem('token') const PUBLIC = ` ...
 - layui计算剩余时间
			
<div id="test"></div> <script> layui.use('util', function(){ var util = ...
 - Linux学习02--Linux一切皆文件
			
Linux学习第二部 Linux一切皆对象 啊啊啊啊啊,今天被学妹说太直了,嘤嘤嘤. 学习linux两三天了,前期感觉并不难,只是命令多,多记记多敲一敲就能都记住了.希望自己能够坚持下去吧! 下面是根 ...
 - 将页面的内容导出使用html2canvas+jsPDF
			
第一首先是要引用 import jsPDF from 'jspdf' import html2canvas from 'html2canvas' import PDFJS from 'pdfjs-di ...
 - logstash-shipper.conf
			
input { file { path => '/data/rsyslog/*/*/*.log' start_position => 'beginning' sincedb_path =& ...
 - oracle 登录
			
命令行登录 sql plus登录 plsql登录 自己电脑登录 既然是登录自己电脑的数据库,肯定是已经安装过了oralce,而且已经创建了数据库等等. 局域网登录 1.必须安装oracleclient ...
 - Java IO(二) 之 InputStream
			
源代码均以JDK1.8作为參考 前言: InputStream实现了两个接口Closeable和AutoCloseable: Closeable:JDK1.5中引入,Closeable接口中仅仅有一个 ...
 - A list is a sequence
			
Like a string, a list is a sequence of values. In a string, the values are characters; in a list, th ...
 - leetcode 新题型----SQL,shell,system design
			
leetcode 主要是一个针对北美的coder人群找工作的代码练习网站,我在2015年初次接触这个网站的时候,总共只有200多道题目,是一个类似acm 的a题网站.这些年变化越来越大,主要是因为找工 ...
 - mybatis如何成功插入后获取自增长的id
			
使用mybatis向数据库中插入一条记录,如何获取成功插入记录的自增长id呢? 需要向xml配置中加上一下两个配置: <insert id="add" useGenerate ...