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

QThread和std::thread

        在 Qt 中, 我们经常会用到多线程,这时候就需要纠结是使用 Qt 的 QThread 还是使用 C++ 标准库的 std::thread。

        这里记录一下我自己的理解,先介绍一下 QThread 和 std::thread 的使用方法,对比一下他们的不同,最后说一下我理解的应该怎么选择这两种方法。


QThread使用方法

        QThread 的使用有两种方法,一种是继承 QThread,然后重写 run() 函数,这种方法适合执行单个任务,比如计算某个耗时操作,执行完即可,不需要线程常驻。在 Qt5 之后 Qt 官方已经不推荐这种使用方法了,所以在这里也不赘述了。

        在 Qt5 之后,推荐的方法是创建一个工作类继承于 QObject,将工作对象通过 movetothread() 函数移动到一个新的线程中,这种方法更符合 Qt 的对象模型,并且更易于管理线程的生命周期和资源。下面是一个示例:

class Worker : public QObject {Q_OBJECT
public:Worker();~Worker();void doWorkA() {qDebug() << "Worker thread ID:" << QThread::currentThreadId();emit sigReadData("doWorkA");}void doWorkB() {qDebug() << "Worker thread ID:" << QThread::currentThreadId();emit sigResultReady();}signals:void sigReadData(QString data);void sigResultReady();
};
QThread *thread = new QThread();
Worker *worker = new Worker();worker->moveToThread(thread);// 连接信号槽
QObject::connect(worker, &Worker::sigReadData, this, &::);
QObject::connect(worker, &Worker::sigResultReady, thread, &QThread::quit);
QObject::connect(worker, &Worker::sigResultReady, worker, &QObject::deleteLater);
QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater); // 线程完成后自动删除qDebug() << "Main thread ID:" << QThread::currentThreadId();thread->start();
worker->doWorkA();
worker->doWorkB();

        这个 Worker 类没有做任何特别的事情,但它包含所有必需的元素。在这个例子中, doWorkA() 被调用时可以做一些你自己的处理,处理完后发送 sigReadData() 给主线程,doWorkB() 完成后它会发出信号 sigResultReady(),然后该信号将连接到 QThread 的槽 quit(),触发 QThread 的事件循环退出。事件循环退出后,QThread::finished() 信号被触发,连接到槽 QObject::deleteLater(),自动删除 QThread 对象。

        顺便说一句,这里要注意的非常重要的一件事是你永远不应该在 QObject 类的构造函数中分配堆对象(使用 new)。如果在构造函数中new,会报错 QObject:Cannot create children for a parent that is in a different thread。这个报错是由于这个 new 分配是在主线程,而不是新的子线程 QThread 实例上的。这意味着新创建的对象是由主线程拥有的,而不是 QThread 实例。所以,应该在 Worker 类的函数或者槽函数中分配此类资源,例如在 doWorkA() 或者doWorkB() 中使用new。在这种情况下,当调用该对象时,该对象将位于新线程实例上,因此新的线程实例将拥有该资源。


std::thread使用方法

        std::thread 是 C++11 引入的标准线程库,用于创建和管理线程。它提供了一种轻量级的方法来实现多线程编程,适合需要高性能和低延迟的应用。以下是 std::thread 的基本使用方法,可以使用下面几种方法创建线程:

#include <iostream>
#include <thread>class MyClass {
public:void memberFunction() {std::cout << "Hello from member function!" << std::endl;}
};void threadFunction() {std::cout << "Thread ID: " << std::this_thread::get_id() << std::endl;
}int main() {// 使用函数指针std::thread t1(threadFunction);std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;if (t1.joinable()) {t1.join();    // 等待线程完成}// 使用成员函数MyClass obj;std::thread t2(&MyClass::memberFunction, &obj); // 传递对象指针if (t2.joinable()) {t2.join();    // 等待线程完成}// 使用lambda表达式std::thread t3([](){std::cout << "Hello from thread!" << std::endl;});if (t3.joinable()) {t3.join();    // 等待线程完成}return 0;
}

        管理线程有两个函数,一个是上面已经使用过的 join(),另一个是 detach():

std::thread t(threadFunction);
t.join(); // 阻塞主线程,直到 t 线程完成
std::thread t(threadFunction);
t.detach(); // 将线程与当前线程分离,允许 t 独立运行
// 注意:必须确保分离的线程在程序退出前完成


QThread和std::thread的选择

        在我看来,QThread 不仅仅是一个简单的线程类,它更像一个线程管理器。提供了与 Qt 框架的无缝集成,特别是与信号槽机制的结合使用,使得多线程编程更加方便和高效。我们可以把部分功能封装在一个工作对象中,然后把这个对象 movetothread,这样通过这个对象调用封装的所有方法,都是在子线程中进行,我只需要通过Qt的信号槽把子线程中我需要的数据传出来接收就可以在主线程或者UI上显示,而不会卡住主线程或者UI。

        例如,我要控制一个打印机或者串口,需要连接设备、发送消息和一直接收消息等功能,我们把这几个功能封装在一个打印机类或者串口类中。创建对象,然后通过 movetothread() 把这个类放到子线程,这样我们就可以把连接、发送接收处理消息这些功能都放到子线程中,而不影响主线程,接收到的消息需要传给主线程并显示的话就发送信号给主线程。

        而对于一些简单的多线程任务,例如并行计算、独立的后台任务等,使用 std::thread 可以更加轻便、直接和高效。std::thread 相对轻量,没有额外的框架依赖,适用于需要高性能和低开销的多线程操作。并且,std::thread 是 C++ 标准的一部分,保证了跨平台的一致性。如果需要在不同的平台上开发和运行代码,std::thread 提供了一种标准化的方法。

        总结一下:

  • 选择 QThread:如果你需要与 Qt 对象和事件循环进行集成。
  • 选择 std::thread:如果你需要一个更通用、更轻量级的多线程解决方案。

相关文章:

QThread和std::thread

在 Qt 中&#xff0c; 我们经常会用到多线程&#xff0c;这时候就需要纠结是使用 Qt 的 QThread 还是使用 C 标准库的 std::thread。 这里记录一下我自己的理解&#xff0c;先介绍一下 QThread 和 std::thread 的使用方法&#xff0c;对比一下他们的不同&#xff0c;最后说一下…...

LeetCode 算法:组合总和 c++

原题链接&#x1f517;&#xff1a;组合总和 难度&#xff1a;中等⭐️⭐️ 题目 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 …...

【两大3D转换SDK对比】HOOPS Exchange VS. CAD Exchanger

在现代工业和工程设计领域&#xff0c;CAD数据转换工具是确保不同软件系统间数据互通的关键环节。HOOPS Exchange和CAD Exchanger是两款备受关注的工具&#xff0c;它们在功能、支持格式、性能和应用场景等方面有着显著差异。 本文将从背景、支持格式、功能和性能、应用场景等…...

Openerstry + lua + redis根据请求参数实现动态路由转发

文章目录 一、需求分析二、准备1、软件安装2、redis-lua封装优化 三、实现1、nginx.conf2、dynamic.lua注意 3、准备两个应用4、访问nginx 四、参数直接传要代理的地址端口 一、需求分析 根据用户访问url的参数&#xff0c;将请求转发到对应指定IP的服务器上。 二、准备 1、…...

数字名片-Pushmall 智能AI数字名片7月更新计划

[数字名片]-商务营销推广助手7月更新计划 数字名片-商务营销推广助手7月更新计划 **2024年 6月完成模块开发优化****实现SaaS框架业务 1、智能名片&#xff1a;创建个人名片、企业名片、商机管理。 2、人脉商圈&#xff1a;附近人脉、就近群脉、好友名片。 3、企微社群&…...

21. Python代码快速查看数组分布

1. 前言 当你已经具备一段可用于快速查看数组分布的Python代码时,你拥有了一项强大的工具来分析和理解你的数据集。这种类型的代码通常会使用可视化库,例如Matplotlib和Seaborn,以直观的方式展示数据分布。这些库允许你创建直方图以观察数据集中的频率分布,以及核密度估计…...

记录些Redis题集(3)

分布式锁 分布式锁是一种用于在分布式系统中实现互斥访问的机制&#xff0c;它可以确保在多个节点、或进程同时访问共享资源。如果没有适当的锁机制&#xff0c;就可能导致数据不一致或并发冲突的问题。 分布式锁需要的介质 需要一个多个微服务节点都能访问的存储介质&#…...

OracleLinux6.9升级UEK内核

方法一: [root@localhost ~]# uname -r 4.1.12-61.1.28.el6uek.x86_64 [root@localhost ~]# rpm -qa | grep kernel-uek kernel-uek-firmware-4.1.12-61.1.28.el6uek.noarch kernel-uek-4.1.12-61.1.28.el6uek.x86_64 [root@localhost ~]# yum list kernel-uek Loaded plug…...

React学习笔记03-----手动创建和运行

一、项目创建与运行【手动】 react-scripts集成了webpack、bable、提供测试服务器 1.目录结构 public是静态目录&#xff0c;提供可以供外部直接访问的文件&#xff0c;存放不需要webpack打包的文件&#xff0c;比如静态图片、CSS、JS src存放源码 &#xff08;1&#xff09…...

ubantu22.04安装OceanBase 数据库

1、管理员启动cmd,运行 sudo bash -c "$(curl -s https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/download-center/opensource/service/installer.sh)" 2、提示如下代表安装完成 3、修改数据库配置文件的密码 sudo vim /etc/oceanbase.cnf 然后保存退…...

【linux】【深度学习】fairseq框架安装踩坑

直接pip install fairseq发现跑代码时候老是容易崩&#xff0c;所以选择用源码编译安装。 python环境选择3.8以上都行&#xff0c;我选择3.10 首先安装torch&#xff0c; 我选择安装pip install torch1.13.1 torchaudio0.13.1以及cuda 11.7 &#xff08;具体cuda根据个人显卡进…...

【Python爬虫教程】第7篇-requests模块的cookies保存和使用

文章目录 为什么要保存cookiesrequests.utils工具类保存cookies到本地文件从本地文件解析cookies使用使用实践 为什么要保存cookies 保存cookies是避免每次都登录获取权限&#xff0c;一遍权限是有过期时间的&#xff0c;不需要每次重复登录&#xff0c;可以将cookies保存起来…...

微信小程序开发基础知识6----使用npm包

一、小程序对npm的支持与限制 目前&#xff0c;小程序中已经支持使用 npm 安装第三方包&#xff0c;从而来提高小程序的开发效率。但是&#xff0c;在小程序中使用npm 包有如下3个限制: ① 不支持依赖于 Node.js 内置库的包 ② 不支持依赖于浏览器内置对象的包 ③ 不支持依赖于…...

如何在element中table的 v-for中 使用slot-scope?

有时候我们需要通过数据库来动态控制表格的列,这样做的好处就是系统中如果有太多的表格项的话,直接这套代码就能通用了,其他的数据库里控制就行,不要太方便了,特别是一些ERP或者供应链的表格,动不动就是几十上百个字段,这时候不要太轻松了,废话不多说,直接上代码: &…...

企业网络实验dhcp-snooping、ip source check,防非法dhcp服务器、自动获取ip(虚拟机充当DHCP服务器)、禁手动修改IP

文章目录 需求相关配置互通性配置配置vmware虚拟机&#xff08;dhcp&#xff09;分配IP服务配置dhcp relay&#xff08;dhcp中继&#xff09;配置dhcp-snooping&#xff08;防非法dhcp服务器&#xff09;配置ip source check&#xff08;禁手动修改IP&#xff09;DHCP中继&…...

20. Python读取.mat格式文件通用函数

1. 前言 在科研和工程领域,MATLAB的.mat文件是一种常见的数据存储格式,用于保存复杂的数组和结构体。Python作为一种强大的编程语言,提供了多种库来读取和处理.mat文件。本文将介绍一个通用的Python函数,用于读取.mat格式文件,并将其内容转换为Python数据结构,以便进一步…...

Cypress UI自动化之安装环境

注&#xff1a;macOS系统 一、git环境 略 二、node环境 1、安装nvm 前提&#xff1a;有装过Homebrew&#xff0c;参考adb使用方法文档 1、安装nvm&#xff1a;首先要保证之前没有安装过node&#xff0c;如果之前安装过&#xff0c;先 brew uninstall node brew install n…...

SpringApplication.java类

Tips: 以下内容根据源码中的注解翻译 SpringApplication SpringApplication可用来从一个Java main方法引导和启动一个Spring应用。默认情况下&#xff0c;SpringApplication按照以下步骤引导你的应用&#xff1a; 创建一个合适的ApplicationContext&#xff08;依赖于你的cl…...

智能招聘系统的AI功能解析

一、引言 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;技术正逐步渗透到各个领域&#xff0c;为企业带来前所未有的变革。在人力资源管理领域&#xff0c;智能招聘系统的出现&#xff0c;不仅大大提高了招聘效率&#xff0c;还为企业带来了更精准、更科…...

AV1技术学习:Translational Motion Compensation

编码块根据运动矢量在参考帧中找到相应的预测块&#xff0c;如下图所示&#xff0c;当前块的左上角的位置为(x0, y0)&#xff0c;在参考帧中找到同样位置(x0, y0)的块&#xff0c;根据运动矢量移动到目标参考块&#xff08;左上角位置为&#xff1a;(x1, y1)&#xff09;。 AV1…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...