Qt多线程之moveToThread()函数

在使用“继承QObject+QThread”实现多线程时,出现了一个BUG,最后发现是对moveToThread()函数理解不到位导致的。为了弄清楚这个问题最好将Demo代码拷贝,跟着跑一遍。

//a.h
#pragma once
#include "c.h"

class A: public QObject
{
    Q_OBJECT
public:
    A();
public:
    void begin();

public:
    QThread* subThread;
    int x;
    C* c;
};
//a.cpp
#include "a.h"
#include <QThread>
#include <QDebug>
#include <QTimer>


A::A():subThread(new QThread)
  ,c(new C)
{
    qDebug() << "1=" << QThread::currentThreadId();
    this->moveToThread(subThread);
    qDebug() << "2=" << QThread::currentThreadId();
    connect(subThread, &QThread::started, this, &A::begin);
}
void A::begin(){
    qDebug() <<"begin()" << QThread::currentThread();
    // QTimer* timer = new QTimer(c);

}
//c.h
#pragma once
#include <QObject>
class C:public QObject{
    Q_OBJECT
public:
    C();
    void print();
};
//c.cpp
#include "c.h"
#include <QThread>
#include <QDebug>
C::C(){}
void C::print(){
    qDebug() << "C=" <<QThread::currentThreadId();
}
//main.cpp
#include "mainwindow.h"
#include "a.h"
#include <QApplication>
#include<QThread>
#include<QDebug>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    A* aa = new A;
    aa->subThread->start();
    return a.exec();
}

一、moveToThread()执行后,当前代码线程没有改变。

在这里插入图片描述
为了方便说明问题,这里引入线程作用域的概念,它表示哪些变量加入该线程。this->moveToThread(subThread) 的作用是将在主线程中类A的对象本身加入子线程subThread。由于moveToThread()只是在将调用者加入到其他线程的作用域里,所以当前线程没有任何变化。需要注意的是,此时A对象同时属于两个线程的作用域:主线程和子线程sunThread。

二、对象执行moveToThread()后,哪些成员加入了子线程

如果想当然的认为 this->moveToThread(subThread) 将this所指对象的全部成员加入到subThread的作用域中,那么就会大错特错。首先考虑A中方法begin(),通过调用可以发现通过信号started调用时,它的线程ID=0x321c,说明 this->moveToThread(subThread) 将对象的方法加入了子线程的作用域。

下面取消代码中的注释:
在这里插入图片描述
然后运行代码,发现程序报错:
在这里插入图片描述
这是因为Qt不允许为线程作用域外的对象创建子对象。同时这说明A的属性 c 并没有加入到子线程subThread中。解决方法有三个:

1、创建对象时不指定父对象

 QTimer* timer = new QTimer(); //这样只适用于一小部分情况

2、对属性对象使用moveToThread加入子线程作用域

c->moveToThread(subThread);	//这是一个简单有效的办法

3、将属性对象的创建放到子线程中执行

void A::begin(){
    qDebug() <<"begin()" << QThread::currentThreadId();
    c = new C;
    QTimer* timer = new QTimer(c);
}

三、C++内存模型

c++内存模型参考内存模型
C++内存分为堆、栈、代码区、全局/静态存储区、常量存储区共5个区域。
结合C++内存模型,可以知道类的方法与类的属性对象存储区域不一样,也就可以解释为什么moveToThread只是将类的方法加入子线程的作用域。

相关推荐

  1. Qt-线2-moveToThread

    2024-06-14 04:20:02       37 阅读
  2. Qt线编程(QThread)

    2024-06-14 04:20:02       26 阅读
  3. QT中使用moveToThread让任务在子线中进行

    2024-06-14 04:20:02       43 阅读
  4. C++线通过成员函数作为线入口

    2024-06-14 04:20:02       55 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-14 04:20:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-14 04:20:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-14 04:20:02       82 阅读
  4. Python语言-面向对象

    2024-06-14 04:20:02       91 阅读

热门阅读

  1. windows安装SQLyog

    2024-06-14 04:20:02       42 阅读
  2. 判断是否是平衡二叉树--c++【做题记录】

    2024-06-14 04:20:02       31 阅读
  3. 警示:AGI竞赛之未来十年

    2024-06-14 04:20:02       24 阅读
  4. 基于 Vue 3 封装一个 ECharts 图表组件

    2024-06-14 04:20:02       28 阅读
  5. Page的基本使用及其原理

    2024-06-14 04:20:02       28 阅读
  6. 【杂记-浅谈MAC地址】

    2024-06-14 04:20:02       24 阅读
  7. vivado HW_SIO_PLL

    2024-06-14 04:20:02       27 阅读
  8. C++和Python相互调用(1)

    2024-06-14 04:20:02       27 阅读
  9. leetcode hot100 之 编辑距离

    2024-06-14 04:20:02       31 阅读
  10. 115. 素数筛选

    2024-06-14 04:20:02       38 阅读
  11. vue封装全局的防抖节流函数

    2024-06-14 04:20:02       32 阅读
  12. 用Python编写自动发送每日电子邮件报告的脚本

    2024-06-14 04:20:02       28 阅读