当前位置: 首页 > news >正文

QThread 与QObject::moveToThread在UI中的应用

1. QThread的两种用法

第一种用法就是继承QThread,然后覆写 virtual void run(), 这种用法的缺点是不能利用信号槽机制。

第二种用法就是创建一个线程,创建一个对象,再将对象moveToThread, 这种可以充分利用信号槽机制,与UI框架完美融合。这与std::thread也是不一样的地方。

2. moveToThread用法讲解

示例地址:MultiThread/QThreadDemo · 沁明/QtDemo - 码云 - 开源中国 (gitee.com)

直接调用 QObject::moveToThread() 函数,将继承自 QObject 的对象移到线程里面。此时该对象的 槽函数运行在另一个线程里面。 也就是说,当有信号绑定到该对象的槽函数的时候,并发送信号,该槽函数就运行在另一个线程里,否则该函数仍然运行在对象所在的线程中。

1)先创建一个QObject的子类。

它要运行的函数都可以在子线程中运行。

worker.h

#ifndef WORKER_H
#define WORKER_H#include <QObject>class Worker : public QObject
{Q_OBJECT
public:explicit Worker(QObject *parent = nullptr);public slots:void workSlot();void msg1Slot(const QString &m1);void msg3Slot(const QString &m3);signals:void msg1(const QString &m1);void msg2(const QString &m2);
};#endif // WORKER_H

 worker.cpp

#include "worker.h"#include <QDebug>
#include <QThread>Worker::Worker(QObject *parent) : QObject{parent} {connect(this, &Worker::msg1, this, &Worker::msg1Slot);
}void Worker::workSlot() {qDebug() << "QThread begin";qDebug() << "child thread id" << QThread::currentThreadId();qDebug() << "QThread end";// 线槽函数已经执行完进入线程exec()中,可以通过发射信号重新让槽函数在线程中执行。也可以通过// quit() 退出线程exec()。
}void Worker::msg1Slot(const QString &m1) {qDebug() << QThread::currentThreadId() << "receive msg1 " << m1;
}void Worker::msg3Slot(const QString &m3) {qDebug() << QThread::currentThreadId() << "receive msg3 " << m3;
}

2)创建worker对象

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow), thread(nullptr) {ui->setupUi(this);worker = new Worker;qDebug() << "主线程" << QThread::currentThreadId();connect(worker, &Worker::msg2, this, &MainWindow::msg2Slot);connect(this, &MainWindow::msg3, worker, &Worker::msg3Slot);
}

直接在窗口构造函数中创建worker对象,程序运行期间这个对象不会被析构。

由于要使用moveToThread函数,所以worker不能设置父对象的,必须为空。

绑定了两个槽函数,分别用来响应消息2和消息3, 但是消息2的槽在窗口对象上,消息3的槽函数在worker对象上。

3)如果不创建子线程,看看3条消息的执行线程在哪?

 如果没有启用子线程的时候,3条消息执行函数都在主线程上。

4)启用子线程之后,3条消息的执行线程是什么?

void MainWindow::on_pushButtonStart_clicked() {qDebug() << "on_pushButtonStart_clicked线程" << QThread::currentThreadId();if (thread)return;thread = new QThread;worker->moveToThread(thread);QObject::connect(thread, &QThread::started, worker, &Worker::workSlot);QObject::connect(thread, &QThread::finished, this,&MainWindow::workerDetach);thread->start();
}

 这里创建了子线程,然后将worker对象移动线程内执行。 

workSlot()执行完毕之后其实线程并没有结束,它会执行exec()进入线程的消息循环

void Worker::workSlot() {qDebug() << "QThread begin";qDebug() << "child thread id" << QThread::currentThreadId();qDebug() << "QThread end";// 线槽函数已经执行完进入线程exec()中,可以通过发射信号重新让槽函数在线程中执行。也可以通过// quit() 退出线程exec()。
}

后面在worker上的信号或者槽绑定的触发都会进行响应。

 使用QThread启动子线程之后,消息1和消息3 的槽函数在子线程上执行了。

但是消息2的槽函数仍在主线程上。

重新复习一下信号槽绑定

Worker::Worker(QObject *parent) : QObject{parent} {connect(this, &Worker::msg1, this, &Worker::msg1Slot);
}

  connect(worker, &Worker::msg2, this, &MainWindow::msg2Slot);connect(this, &MainWindow::msg3, worker, &Worker::msg3Slot);

可以看出槽函数的执行线程就是对象所在的线程。

在创建了子线程之后,worker的执行线程已经发生了变化,所以消息1、3执行线程也变成了子线程。

5)停止子线程之后,恢复原来线程

QObject::connect(thread, &QThread::finished, this,&MainWindow::workerDetach);void MainWindow::workerDetach() {qDebug() << "workerDetach线程" << QThread::currentThreadId();worker->moveToThread(QThread::currentThread());
}

设置在线程退出之后重新移动对象到主线程。

http://www.lryc.cn/news/378880.html

相关文章:

  • 安卓逆向案例——X酷APP逆向分析
  • 创新案例|星巴克中国市场创新之路: 2025目标9000家店的挑战与策略
  • 计算机网络 MAC地址表管理
  • 【免费API推荐】:各类API资源免费获取【11】
  • 技术驱动会展:展位导航系统的架构与实现
  • 适用于轨道交通专用的板卡式网管型工业以太网交换机
  • excel基本操作
  • C++系统相关操作2 - 获取系统环境变量
  • 适合小白学习的项目1906java Web智慧食堂管理系统idea开发mysql数据库web结构java编程计算机网页源码servlet项目
  • AI通用大模型不及垂直大模型?各有各的好
  • 农产品价格信息系统小程序
  • 【LLM-多模态】高效多模态大型语言模型综述
  • ASP .Net Core创建一个httppost请求并添加证书
  • Redis入门篇
  • 变电站智能巡检机器人解决方案
  • Linux Kernel入门到精通系列讲解(QEMU-虚拟化篇) 2.5 Qemu实现RTC设备
  • 【自动驾驶】通过下位机发送的加速度、角速度计算机器人在世界坐标系中的姿态
  • Python 设计模式(第2版) -- 第四部分(其他设计模式)
  • gitlab升级16.11.3-ee
  • 剑指offer 算法题(搜索二维矩阵)
  • SaaS平台数据对接为什么要选择API对接?
  • 力扣136. 只出现一次的数字
  • 重学java 74.Lombok的使用
  • 数据结构6---树
  • 一键制作,打造高质量的数字刊物
  • Java面试题:对比继承Thread类和实现Runnable接口两种创建线程的方法,以及它们的优缺点
  • 编译原理-各章典型题型+思路求解
  • 【绝对有用】C++ vector排序
  • linux——VScode安装
  • X-LoRA:高效微调 LoRA 系列,实现不同领域知识专家混合模型