QThread 与QObject::moveToThread利用Qt事件循环在子线程执行多个函数
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());
}
设置在线程退出之后重新移动对象到主线程。

相关文章:
QThread 与QObject::moveToThread利用Qt事件循环在子线程执行多个函数
1. QThread的两种用法 第一种用法就是继承QThread,然后覆写 virtual void run(), 这种用法的缺点是不能利用信号槽机制。 第二种用法就是创建一个线程,创建一个对象,再将对象moveToThread, 这种可以充分利用信号槽机制ÿ…...
6-2 归并排序
6-2 归并排序 分数 10 全屏浏览 切换布局 作者 软件工程DS&A课程组 单位 燕山大学 以下代码采用分而治之算法实现归并排序。请补充函数mergesort()的代码。提示:mergesort()函数可用递归实现,其中参…...
Java NIO(一) 概述
NIO主要用于以少量线程来管理多个网络连接,处理其上的读写等事件。在大量连接情况下,不管是效率还是空间占用都要优于传统的BIO。 Java NIO 由以下几个核心部分组成: Channel Buffer Selector Selector 如果你的应用打开了多个连接&#x…...
JUC线程池最佳实践
参考:Java 线程池最佳实践 | JavaGuide 使用构造函数创建线程池。【使用有界队列,控制线程创建数量】 SpringBoot 中的 Actuator 组件 / ThreadPoolExecutor 的相关 API监控线程池运行状态 是不同的业务使用不同的线程池【父子任务用同一个线程池容易死…...
2024最新版Node.js下载安装及环境配置教程(非常详细)
一、进入官网地址下载安装包 官网:Node.js — Run JavaScript Everywhere 其他版本下载:Node.js — Download Node.js (nodejs.org) 选择对应你系统的Node.js版本 二、安装程序 (1)下载完成后,双击安装包…...
计算机网络5:运输层
概述 进程间基于网络的通信 计算机网络中实际进行通信的真正实体,是位于通信两端主机中的进程。 如何为运行在不同主机上的应用进程提供直接的逻辑通信服务,就是运输层的主要任务。运输层协议又称为端到端协议。 运输层向应用层实体屏蔽了下面网络核心…...
昂科烧录器支持HangShun航顺芯片的32位微控制器HK32F030C8T6
芯片烧录行业领导者-昂科技术近日发布最新的烧录软件更新及新增支持的芯片型号列表,其中HangShun航顺芯片的32位微控制器HK32F030C8T6已经被昂科的通用烧录平台AP8000所支持。 HK32F030C8T6使用ARM Cortex-M0内核,最高工作频率96 MHz,内置最…...
纯css星空动画
让大家实现一个这样的星空动画效果,大家会怎么做? js,不! 其实使用css就能写 我也不藏着掖着,源码直接放下面了 <script setup></script><template><div class"box"><div v-for"i in 5" :key"i" :class"layer…...
使用Apache Flink实现实时数据同步与清洗:MySQL和Oracle到目标MySQL的ETL流程
使用Apache Flink实现实时数据同步与清洗:MySQL和Oracle到目标MySQL的ETL流程 实现数据同步的ETL(抽取、转换、加载)过程通常涉及从源系统(如数据库、消息队列或文件)中抽取数据,进行必要的转换࿰…...
postman教程-22-Newman结合Jenkins执行自动化测试
上一小节我们学习了Postman Newman运行集合生成测试报告的方法,本小节我们讲解一下Postman Newman结合Jenkins执行自动化测试的方法。 在软件开发过程中,持续集成(CI)是一种实践,旨在通过自动化的测试和构建过程来频繁…...
uniapp实现tabBar功能常见的方法
在 UniApp 中实现 Tab 功能通常涉及到使用 <navigator> 组件结合 tabBar 配置,或者通过自定义的视图切换逻辑来实现。以下是两种常见的实现方式: 1. 使用 tabBar 配置 UniApp 支持在 pages.json 文件中配置 tabBar,以在应用的底部或顶…...
智慧在线医疗在线诊疗APP患者端+医生端音视频诊疗并开处方
智慧在线医疗:音视频诊疗新纪元 🌐 智慧医疗新篇章 随着科技的飞速发展,智慧医疗正逐步走进我们的生活。特别是在线医疗,凭借其便捷、高效的特点,已成为许多患者的首选。而其中的“智慧在线医疗患者端医生端音视频诊疗…...
攻防平台搭建与简易渗透工具箱编写
知识点:攻防平台搭建,虚拟机的网络模式详解,安全脚本编写 虚拟机的网络模式: 虚拟机(VM)的网络模式决定了虚拟机与宿主机以及外部网络之间的连接方式。不同的虚拟化平台(如VMware, VirtualBox,…...
SQL EXISTS 关键字的使用与理解
SQL EXISTS 关键字的使用与理解 SQL(Structured Query Language)是一种用于管理关系数据库管理系统(RDBMS)的标准编程语言。在SQL中,EXISTS关键字是一个逻辑运算符,用于检查子查询中是否存在至少一行数据。…...
开源低代码平台,JeecgBoot v3.7.0 里程碑版本发布
项目介绍 JeecgBoot是一款企业级的低代码平台!前后端分离架构 SpringBoot2.x,SpringCloud,Ant Design&Vue3,Mybatis-plus,Shiro,JWT 支持微服务。强大的代码生成器让前后端代码一键生成! JeecgBoot引领…...
名侦探李先生第一话:谁是真正的凶手(只出现一次的数字相关题解(力扣)+位操作符回忆)
引子:我们在之前的案子中破解过基础的单身狗问题,那面对更有挑战的案子,且看李先生如何破局,那下凶手! 复习: 1,位操作符: 正整数原,反,补码都相同 首位是…...
【PA交易】BackTrader(一): 如何使用实时tick数据和蜡烛图
背景和需求 整合Tick数据是PA交易的回测与实盘基本需求。多数交易回测框架往往缺乏对大规模Tick数据直接而全面的支持。Tick数据因其体量庞大(例如,某棕榈油主力合约四年间的数据达8GB)为结合价格趋势与PA分析带来挑战,凸显了实时…...
HTML(16)——边距问题
清楚默认样式 很多标签都有默认的样式,往往我们不需要这些样式,就需要清楚默认样式 写法: 用通配符选择器,选择所有标签,清除所有内外边距选中所有的选择器清楚 *{ margin:0; padding:0; } 盒子模型——元素溢出 作…...
【Godot4自学手册】第四十二节实现拖拽进行物品交换和数量叠加
这一节我们主要学习背包系统中的物品拖拽后,物品放到新的位置,或交换物品位置,如果两个物品属于同一物品则数量相加。具体效果如下: 一、修改item.tscn场景 给item.tscn场景的根节点Item添加Label子节点,命名为Numv…...
存储系统概述
目录 层次结构 存储器的分类 存储器的编址和端模式 存储器端模式 存储器的技术指标 1. 存储容量 示例: 2. 访问速度 访问速度的表现形式: 示例: 3. 功耗 示例: 4. 可靠性 可靠性指标: 示例:…...
2026技术展望】Python与AI的深度融合:从“能用”到“好用”的质变之年
🔥个人主页:北极的代码(欢迎来访) 🎬作者简介:java后端学习者 ❄️个人专栏:苍穹外卖日记,SSM框架深入,JavaWeb ✨命运的结局尽可永在,不屈的挑战却不可须臾或…...
Nomad与Consul集群搭建实战指南
1. 为什么选择NomadConsul组合? 如果你正在寻找一套轻量级、易上手的分布式系统解决方案,Nomad和Consul这对黄金搭档绝对值得考虑。我最早接触这个组合是在三年前的一个物联网项目中,当时我们需要在20台边缘计算设备上动态部署服务࿰…...
手把手教你部署OpenClaw(小龙虾),打造专属AI数字员工
2026年,开源AI智能体OpenClaw(国内昵称“小龙虾”)凭借独特的“数字员工”定位迅速崛起,GitHub星标一路攀升至28万,成为当下最受开发者和办公人群青睐的开源AI项目。 一、OpenClaw核心优势解析 OpenClaw能在众多开源…...
Hadoop 3.3.5 分布式集群部署
环境准备与规划硬件要求:3台节点(1主2从)软件依赖:JDK 8、SSH免密登录目录规范:统一安装路径(如/opt/module),用户权限管理Hadoop安装与核心配置一定要检查一下,ssh 能不…...
探索MariaDB中的JSON处理
在数据库管理中,处理JSON数据逐渐变得重要,尤其是在需要从复杂的JSON结构中提取信息时。今天,我们将深入探讨如何在MariaDB中使用JSON_SEARCH函数来检查JSON对象中的布尔值true。通过实例,我们将展示如何使用此函数来简化查询过程。 JSON数据的结构 假设我们有一个JSON对…...
安卓手机秒变AI开发神器:Aid Learning零基础图形化Linux环境搭建指南
安卓手机秒变AI开发神器:Aid Learning零基础图形化Linux环境搭建指南 在移动互联网时代,开发者对便携开发环境的需求与日俱增。传统Termux虽然功能强大,但配置复杂、缺乏图形界面,让许多初学者望而却步。Aid Learning的出现彻底改…...
万象视界灵坛实战教程:广告Banner图受众情绪倾向语义解析实践
万象视界灵坛实战教程:广告Banner图受众情绪倾向语义解析实践 1. 平台介绍与核心能力 万象视界灵坛是一款基于OpenAI CLIP技术的高级多模态智能感知平台。它将复杂的图像语义分析过程转化为直观的交互体验,特别适合需要快速理解视觉内容情感倾向的营销…...
【实验原理深度解析】弗兰克-赫兹实验:如何用电子“碰撞”揭示原子能级的秘密
1. 电子与原子的"对话":弗兰克-赫兹实验的设计哲学 想象你站在一个漆黑的房间里,向对面墙壁投掷网球。如果墙壁是实心的,球会直接弹回;但如果墙上有一排高度不同的窗口,球只有达到特定速度才能穿过对应高度的…...
Node.js——事件的监听与触发
事件的监听与触发1、EventEmitter对象2、添加和触发监听事件2.1、添加监听事件2.2、添加单次监听事件2.3、触发监听事件3、删除监听事件1、EventEmitter对象 在JavaScript中,通过事件可以处理许多用户的交互,比如鼠标的单击、键盘按键的按下、对鼠标移动…...
无需配置环境!MinerU镜像一键部署,即刻体验智能文档解析
无需配置环境!MinerU镜像一键部署,即刻体验智能文档解析 1. 为什么选择智能文档解析? 在日常办公和学习中,我们经常需要处理各种文档资料:PDF报告、扫描合同、学术论文、财务报表等。传统方式要么需要手动输入&#…...
