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());
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/34684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 支持的多种日期和时间类型

MySQL 支持的多种日期和时间类型 MySQL 支持多种日期和时间类型&#xff0c;包括&#xff1a; 1. DATE: 存储日期值&#xff08;年、月、日&#xff09;&#xff0c;格式为 YYYY-MM-DD&#xff0c;例如&#xff1a;2024-06-11。 2. TIME: 存储时间值&#xff08;小时、分钟、秒…

199.罗马数字转整数(力扣)

代码解决 class Solution { public:// 定义一个哈希表来存储罗马数字符号及其对应的整数值unordered_map<char, int> res {{I, 1},{V, 5},{X, 10},{L, 50},{C, 100},{D, 500},{M, 1000},};// 将罗马数字字符串转换为整数的函数int romanToInt(string s) {int num 0; …

ElasticSearch安装、配置详细步骤

一、环境及版本介绍 操作系统&#xff1a; Windows 10 软件版本&#xff1a; elasticsearch-7.17.22、kibana-7.17.22、IK-7.17.22 开发环境选择软件版本应提前考虑正式系统得环境&#xff0c;否则会产生软件与服务器环境不兼容得问题出现&#xff0c;ElasticSearch与环境支…

【机器学习300问】132、自注意力机制(Self-Attention)和传统注意力机制(Attention)的区别?

最近学习注意力机制的时候&#xff0c;发现相同的概念很多&#xff0c;有必要给这些概念做一下区分&#xff0c;不然后续的学习可能会混成一团。本文先区分一下自注意力机制和传统注意力机制。我会先直接给出它们之间有何区别的结论&#xff0c;然后通过一个例子来说明。 一、…

【C++题解】1711. 输出满足条件的整数1

问题&#xff1a;1711. 输出满足条件的整数1 类型&#xff1a;简单循环 题目描述&#xff1a; 有这样的两位数&#xff0c;其十位上的数字比个位上的数字要大&#xff0c;且十位和个位上的数字之和为偶数&#xff0c;请找出所有的满足条件的 2 位数。 输入&#xff1a; 无。…

Spring IOC 控制反转总结

Spring IOC 控制反转总结 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在现代Java开发中&#xff0c;Spring框架已成为不可或缺的工具&#xff0c;其核心概…

想法是否可行(学习笔记)

切入时机 进入市场的切入时机是否成熟&#xff0c;现有的技术手段和基础设施是否能够满足需求&#xff0c;用户的使用习惯和心理认知是怎么样的&#xff1f; 运营推广 有哪些渠道进行运营推广&#xff0c;产品的本身是否足够好&#xff0c;是否有足够的留存&#xff0c;是否能…

前端算法--括号⽣成

题⽬描述 数字 n 代表⽣成括号的对数&#xff0c;请你设计⼀个函数&#xff0c;⽤于能够⽣成所有可能的并且 有效的 括号组合。 示例&#xff1a; 输⼊&#xff1a; n 3 输出&#xff1a; [ "((()))", "(()())", "(())()", "()(()…

Unity的Excel转表工具

该Excel工具主要由Python语言完成&#xff0c;版本为3.x 主要功能&#xff1a; 1.转换后的数据存储结构为二进制。 2.excel文件可以选择多种数据类型&#xff1a;int、float、string、一维&#xff08;int、float、string&#xff09;、二维int、Map&#xff08;int/int、in…

Hive基础知识(十九):Hive 自定义函数

1. 自定义函数 1&#xff09;Hive 自带了一些函数&#xff0c;比如&#xff1a;max/min 等&#xff0c;但是数量有限&#xff0c;自己可以通过自定义 UDF 来方便的扩展。 2&#xff09;当 Hive 提供的内置函数无法满足你的业务处理需要时&#xff0c;此时就可以考虑使用用户自…

xcode15 升级大坑

Q&#xff1a;iOS17 SDK 模拟器 7个多G,一直安装失败&#xff0c;都是网络中断&#xff0c;试了第六次竟然硬生生下载并安装成功。如果实在不成功尝试一下步骤&#xff1a; 1.直接在Apple官网找到你要下载的文件&#xff0c;https://developer.apple.com/download/all/ 2.下…

golang常用库之-godotenv库从.env文件读取配置数据

文章目录 golang常用库之-从.env文件读取配置数据godotenv库使用 golang常用库之-从.env文件读取配置数据 godotenv库从.env文件中读取配置&#xff0c; 然后存储到程序的环境变量中。在代码中可以使用读取非常方便。 godotenv库 官方&#xff1a;https://pkg.go.dev/github…

图的搜索。

用邻接表作为图的存储结构建立一个图&#xff0c;并对此图分别进行深度优先搜索和广度优先搜索遍历。 #include<stdio.h> #include<stdlib.h> #define MAX_VERTEM_NUM 10 #define INFINITY 32768 typedef enum{ DG,DN,UDG,UDN }graghKind; //digraph D…

【AI应用探讨】—小型神经网络应用场景

目录 1. 移动设备 2. 物联网设备 3. 无人驾驶 4. 可穿戴设备 5. 其他领域 1. 移动设备 a. 图像识别 用例&#xff1a;在智能手机和平板电脑上运行的实时图像识别应用&#xff0c;如人脸识别、物体识别等。优势&#xff1a;小型神经网络能够在这些设备上快速运行&#xff…

Visual Studio Code 配置 java/maven 环境(Windows版)

在Windows版Visual Studio Code&#xff08;VS Code&#xff09;中配置Java和Maven环境&#xff0c;可以按照以下步骤进行&#xff1a; 1. 安装JDK 确保已经安装了JDK 8或更高版本。建议访问Oracle官网或OpenJDK官网下载相应版本的JDK。安装JDK后&#xff0c;配置系统环境变量…

OpenFeign 的请求处理流程

流程 1. 定义 Feign 客户端接口 首先&#xff0c;开发者需要定义一个 Feign 客户端接口&#xff0c;并使用 FeignClient 注解进行配置。例如&#xff1a; FeignClient(name "aService", url "http://localhost:8080") public interface ServiceProvid…

Python | Leetcode Python题解之第169题多数元素

题目&#xff1a; 题解&#xff1a; class Solution:def majorityElement(self, nums: List[int]) -> int:count 0candidate Nonefor num in nums:if count 0:candidate numcount (1 if num candidate else -1)return candidate

linux下编译安装python3

目录 一、注意事项 二、安装前依赖安装 三、下载python3 四、编译安装 五、查看是否安装成功 一、注意事项 linux下一般会自带python2&#xff0c;很多程序会依赖python2,所以要在python2基础上安装python3 二、安装前依赖安装 yum -y install zlib* yum install libffi-d…

Jotai-灵活的、细粒度的 React 状态管理库

一、Jotai是什么&#xff1f; Jotai 是一个用于 React 的轻量级状态管理库&#xff0c;名字来源于日语中的 "状態" (Jōtai)&#xff0c;意思是“状态”。它的设计目标是提供一种简单、灵活且强大的方式来管理 React 应用中的状态&#xff0c;特别适合处理复杂的状态…

【漏洞复现】用友 U9 PatchFile.asmx 任意文件上传漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…