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

QThread 爬坑之旅(三种办法解决QObject: Cannot create children for a parent that is in a different thread)的更多相关文章

  1. java——多线程的实现方式、三种办法解决线程赛跑、多线程数据同步(synchronized)、死锁

    多线程的实现方式:demo1.demo2 demo1:继承Thread类,重写run()方法 package thread_test; public class ThreadDemo1 extends ...

  2. 记一次项目使用webuploader爬坑之旅

       因前端页面开发使用的为VUE开发,又要支持IE9,遂只有基于webuploader封装一个上传组件.地址:https://github.com/z719725611/vue-upload-web ...

  3. PHP修改memory_limit的三种办法

     PHP修改memory_limit的三种办法 2010-06-11 10:57:11 分类: 可能是分词程序的问题.只要搜索的字段达到十个汉字以上,就会出现诸如以下的错误 Fatal error: ...

  4. 三种方法解决android帮助文档打开慢

    三种方法解决android帮助文档打开慢   经查是因为本地文档中的网页有如下两段js代码会联网加载信息,将其注释掉后就好了 <link rel="stylesheet" h ...

  5. Oracle用户解锁的三种办法及默认的用户与密码

    ORA-28000: the account is locked-的解决办法 2009-11-11 18:51 ORA-28000: the account is locked 第1步:使用PL/SQ ...

  6. 解决Viewpager满屏不能自适应填充内容的三种办法

    由于排版问题,本人博客园同名博文地址为:http://www.cnblogs.com/bill-technology/articles/3143667.html 很多Android开发者在使用View ...

  7. WEB项目会话集群的三种办法

    web集群时session同步的3种方法 在做了web集群后,你肯定会首先考虑session同步问题,因为通过负载均衡后,同一个IP访问同一个页面会被分配到不同的服务器上, 如果session不同步的 ...

  8. 部署vc2008开发的程序(三种办法,但是我觉得这种办法最不好)

    如果你编译了一个VC2008的默认的CRT/MFC的应用程序,如果目标部署电脑上没有安装相应的VC2008的动态库,当运行你的程序的时 个,会出现如下错误信息.   这是因为程序使用了基于VC2008 ...

  9. Android 再按一次退出程序三种办法

    在Xamarin android中双击返回键退出程序的第一种做法 思路就是当用户按下返回键的时间超过两秒就退出,根据Keycode.Back判断用户按下的是返回键,重写这个OnKeyDown Date ...

随机推荐

  1. RegExp javascript正则表达式 :

    传统的查找字符串中的相关的字符 :<script type="text/javascript">var str='aaa23uihjkikh666jhjhk888kuh ...

  2. Markdown语法简记

    目录 一.标题 1. 六个级别的标题 2. 主.副两级标题 二.根据标题生成文档结构大纲 三.字体 1. 斜体 2. 粗体 3. 倾斜加粗 4. 行首缩进 5. 删除线 四.引用块 五.代码块 1. ...

  3. [CTSC2016]单调上升路径

    题目:UOJ#201. 题目大意:给定n个点(n是偶数)的完全图,现在要你给每条边确定一个权值(互不相等),使得最长的单调上升路径最短.现在要你输出边的权值. 一条路径被称为单调上升的,如果沿着它走时 ...

  4. mariadb-增删改查怎么用

    MariaDB 数据类型 MariaDB数据类型可以分为数字,日期和时间以及字符串值. 使用数据类型的原则:够用就行,尽量使用范围小的,而不用大的 常用的数据类型 整数:int, (bit比整数还要小 ...

  5. Valgrind的安装及简单使用

    1.获取源码 wget http://www.valgrind.org/downloads/valgrind-3.14.0.tar.bz2 2.解压缩 tar -jxvf valgrind-3.14. ...

  6. 关于vue事件监听的一个问题

    由于新工作需要用vue,所以最近接触最多的也是vue,因为之前一直在用react,所以对于vue上手还是很快的.我也尽量找一些他们两个的异同点,除了多了一些辅助用的方法以外,最大的不同应该是对于组件间 ...

  7. linux操作---cd

    cd命令用于切换工作路径,格式是cd [选项][参数]: [选项] -p  如果切换的工作目录是一个符号连接,直接切换到符号连接指向的目标目录: -L  如果切换的工作目录是一个符号连接,直接切换到符 ...

  8. redis为什么选择单线程工作模型

    1.先说一下为什么出现进程,线程 进程:在计算机发明之初就发现,在输入数据时(I/O速度慢),CPU是空闲的,这样就浪费了CPU资源,为了充分利用CPU资源,发明了进程,在输入程序A的数据时,程序B在 ...

  9. C++容器(二):关联容器简介

    关联容器(associative container)与顺序容器的本质区别在于:关联容器通过键(Key)存储和读取元素,而顺序容器则通过元素在容器中的位置顺序存储和访问元素.虽然,关联容器的大部分行为 ...

  10. js 判断是否滚动到底部

    $(window).scroll(function(){ var scrollTop = $(this).scrollTop(); //scrollTop() 方法返回或设置匹配元素的滚动条的垂直位置 ...