Qt:多线程
目录
初识Qt多线程
QThread常用API
QThread的使用
Qt中的锁
条件变量和信号量
初识Qt多线程
Qt 多线程 和 Linux 中的线程本质是一个东西
Linux 中学过的 多线程 APl,Linux 系统提供的 pthread 库
Qt 中针对系统提供的线程 API 重新封装了
C++11 中,也引入了线程 std:thread
Qt API 设计的时候,博采众家之长:
- Linux 原生的多线程 API,设计的非常差,使用起来非常不方便的(也是C语言本身的局限性引起的)
实际开发中,很少会使用原生 api - C++ 的 std::thread 要比 Linux 的 API 要好一些
- Qt 中的多线程 API,还要更好一点,其实参考了 Java 中的线程库 API 的设计方式
在 Qt 中,多线程的处理一般是通过 QThread类 来实现
QThread 代表一个在应用程序中可以独立控制的线程,也可以和进程中的其他线程共享数据
OThread 对象管理程序中的一个控制线程
QThread要想创建线程,就需要创建出这样类的实例
创建线程的时候,需要重点指定线程的入口函数
Qt中,使用方式就是创建一个 QThread 的子类,重写其中的 run 函数,起到指定入口函数的方式(多态)
QThread常用API

QThread的使用
之前基于定时器,写过倒计时这样的程序,也可以通过线程,来完成类似的功能
定时器内部本质上也是可以基于多线程来实现的(Qt 的定时器是否基于多线程,不太清楚)
创建另一个线程,新线程中进行计时(搞一个循环,每循环一次,sleep 1s,sleep 完成,就可以更新界面了)
首先图形化界面的方式拖动一个 LCD Number,初始值设为10:

接下来创建一个类 Thread,继承自 QThread:

由于存在线程安全问题,多个线程同时对于界面的状态进行修改,此时就会导致界面就出错了
Qt 选择了 一刀切,针对界面的控件状态进行任何修改,务必在主线程中执行
在 thread.h 中,声明需要重写的 run 函数,再声明一个信号:

run 函数的实现:

接着在 widget.h 中创建一个 Thread 对象 thread,和一个处理信号的槽函数 handle:

Widget 构造函数如下:

槽函数 handle:

此时运行程序,就完成了倒计时的功能:
下面总结一下执行流程:
- 主线程启动新线程
- 新线程每隔一秒发送一次信号
- 主线程收到信号后,调用槽函数修改倒计时的值
Qt中的锁
说起多线程,最需要注意的就是线程安全问题,因为多线程程序太复杂了
而解决线程安全问题,最主要的措施就是加锁
把多个线程要访问的公共资源,通过锁保护起来 => 把并发执行变成串行执行
关于锁,Linux、C++、Qt 都有一套规定:
- Linux:mutex 互斥量
- C++11 引入 std:.mutex
- Qt 同样也提供了对应的锁 QMutex,来针对系统提供的锁进行封装
与 C++ 的 std:.mutex 相差不大,lock 加锁,unlock 解锁
下面演示 Qt 中锁的使用
创建好项目后,同样创建一个新的类 Thread,继承自 QThread:
因为下面想要两个线程对同一个变量进行操作,所以在 Thread 中添加一个静态成员 num,并声明重写的 run 方法:
注意 num 需要类内声明,类外初始化(在 thread.cpp 中初始化:int Thread::num = 0;)

run 方法就是循环5万次,每次给 num++:

下面在 widget.cpp 中编写构造函数的逻辑:

此时打印的结果如下:

并不是我们预期的10万,说明是存在 bug,说明是存在线程安全问题的
所以需要加锁处理,为了让两个线程用同一把锁,就将这个锁设为 static 的:
同样需要在 thread.cpp 中定义:QMutex Thread::mutex;

有了锁 mutex 后,就可以在 run 函数中 num++ 前后进行加锁和解锁操作:

此时再次运行程序,num 的值就是我们期望的10万了:

上面虽然结果正确了,但是这里的锁很容易忘记释放,忘记 unlock
实际开发中,加锁之后涉及到的逻辑可能很复杂,下面很容易就忘记释放锁
在 C++ 中释放动态内存也存在类似的问题,在释放前如果有 return 或 抛异常,就会出问题
C++ 在内存这里采用智能指针进行处理,而锁的释放,C++11 引入了 std::lock_guard,就相当于是 std::mutex 的智能指针,也是借助 RAII 机制
所以 std::lock_guard 一般如下所示:
{std::lock_guard(mutex);// 执行各种逻辑
}
大括号执行完毕, guard 变量的生命周期结束,就会在析构的时候,执行 unlock 了
上述方案,Qt也参考过来了,即 QMutexLocker
所以上述的 run 函数改为:

此时每次循环结束,locker 就会自动解锁,每次进入循环又会自动加锁,不会出现忘记解锁,或是有 return 和 异常 跳过解锁的情况
运行程序,依旧能够执行出正确的结果:

注意:
Qt 的锁 和 C++ 标准库中的锁,本质上都是封装的系统提供的锁
编写多线程程序的时候,可以使用 Qt 的锁,也可以使用 C++的锁,C++的锁也是可以锁 Qt 的线程的(虽然混着用也行,一般不建议)
条件变量和信号量
这里的条件变量和信号量,和 Linux 中谈到的条件变量/信号量完全一致
条件变量
多个线程之间的调度是无序的,为了能够一定程度的干预线程之间的执行顺序,引入条件变量
QWaitCondition
- wait
- wake
- wakeAll
要想使用条件变量,首先要进行加锁,因为在 wait 中就会进行 释放锁 + 等待
要想释放锁, 前提就是先获取到锁
并且还要搭配 while 循环,判断条件是否成立:
// 判定线程继续执行的条件是否成立,不成立就进行 wait 等待
while(!conditionFullfilled())
{condition.wait(&mutex);//等待条件满足并释放锁
}
这里要使用while 判定而不是 if,是因为:
唤醒之后,需要再确认一下当前条件是否真的成立了,wait 可能被提前唤醒的(可能被信号打断了)
信号量
这里谈到的信号量,其实还可以进行进程之间的控制
当然,也同样可以作为同一个进程内部的线程之间的通信方式
信号量其实就是计数器,描述了可用资源的个数
使用示例:
// 同时允许两个线程访问共享资源
QSemaphore semphore(2);
// 在需要访问共享资源的线程中
semaphore.acquire(); // 尝试获取信号量,若已空则阻塞(P)
// 访问共享资源
....
semaphore.release(); // 释放信号量(V)
// 在另一个线程中进行类似操作
Qt:多线程相关到此结束
相关文章:
Qt:多线程
目录 初识Qt多线程 QThread常用API QThread的使用 Qt中的锁 条件变量和信号量 初识Qt多线程 Qt 多线程 和 Linux 中的线程本质是一个东西 Linux 中学过的 多线程 APl,Linux 系统提供的 pthread 库 Qt 中针对系统提供的线程 API 重新封装了 C11 中,…...
算法系列之广度优先搜索解决妖怪和尚过河问题
在算法学习中,广度优先搜索(BFS)是一种常用的图搜索算法,适用于解决最短路径问题、状态转换问题等。本文将介绍如何利用广度优先搜索解决经典的“妖怪和尚过河问题”。 问题描述 有三个妖怪和三个和尚需要过河。他们只有一条小船…...
详解常用集合和映射中的线程安全问题
1. 前言 在 Java 中,集合和映射是常用的数据结构,它们分为线程安全和线程不安全两类。我们常用的集合包括:ArrayList、HashSet、CopyOnWriteArrayList、CopyOnWriteArraySet。常用的映射包括:HashMap、ConcurrentHashMap、Hashta…...
计算机毕业设计SpringBoot+Vue.js车辆管理系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
【js逆向】iwencai国内某金融网站实战
地址:aHR0cHM6Ly93d3cuaXdlbmNhaS5jb20vdW5pZmllZHdhcC9ob21lL2luZGV4 在搜索框中随便输入关键词 查看请求标头,请求头中有一个特殊的 Hexin-V,它是加密过的;响应数据包中全是明文。搞清楚Hexin-V的值是怎么生成的,这个值和cooki…...
安卓设备root检测与隐藏手段
安卓设备root检测与隐藏手段 引言 安卓设备的root权限为用户提供了深度的系统控制能力,但也可能带来安全风险。因此,许多应用(如银行软件、游戏和流媒体平台)会主动检测设备是否被root,并限制其功能。这种对抗催生了ro…...
【音视频 | AAC】AAC编码库faac介绍、使用步骤、例子代码
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
Unity摄像机跟随物体
功能描述 实现摄像机跟随物体,并使物体始终保持在画面中心位置。 实现步骤 创建脚本:在Unity中创建一个新的C#脚本,命名为CameraFollow。 代码如下: using UnityEngine;public class CameraFollow : MonoBehaviour {public Tran…...
dp_走方格(包含dfs分析,记忆化搜索)
类似题目解析:dp_最长上升子序列(包含dfs分析,记忆化搜索)-CSDN博客 题目链接:2067. 走方格 - AcWing题库 题目图片: 分析题目(dfs) 这个题目说有一个行为n行,列为m列…...
软考 中级软件设计师 考点笔记总结 day01
文章目录 软考1.0上午考点下午考点 软考1.11、数值及其转换2、计算机内数据表示2.1、定点数 - 浮点数2.2、奇偶校验 和 循环冗余校验 (了解)2.3、海明码 (掌握)2.4、机器数 软考1.0 上午考点 软件工程基础知识: 开发模型、设计原则、测试方…...
如何用Kimi生成PPT?秒出PPT更高效!
做PPT是不是总是让你头疼?😩 快速制作出专业的PPT,今天我们要推荐两款超级好用的AI工具——Kimi 和 秒出PPT!我们来看看哪一款更适合你吧!🚀 🥇 Kimi:让PPT制作更轻松 Kimi的生成效…...
K8S学习之基础十八:k8s的灰度发布和金丝雀部署
灰度发布 逐步扩大新版本的发布范围,从少量用户逐步扩展到全体用户。 特点是分阶段发布、持续监控、逐步扩展 适合需要逐步验证和降低风险的更新 金丝雀部署 将新版本先部署到一小部分用户或服务器,观察其表现,再决定是否全面推广。 特点&…...
Java 深度复制对象:从基础到实战
目录 一、深度复制的概念二、实现深度复制的方法1. 使用序列化2. 手动实现深度复制 三、总结 在 Java 编程中,对象的复制是一个常见的需求。然而,简单的复制操作(如直接赋值)只会复制对象的引用,而不是创建一个新的对象…...
【前端】webstorm创建一个导航页面:HTML、CSS 和 JavaScript 的结合
文章目录 前言一、项目结构二、HTML 结构三、CSS 样式四、JavaScript 功能五、现代化风格优化htmlcssjavascript运行效果 总结 前言 在现代网页开发中,一个良好的导航栏是提升用户体验的重要组成部分。在这篇文章中,我将向您展示如何创建一个简单而完整…...
AI编程: 一个案例对比CPU和GPU在深度学习方面的性能差异
背景 字节跳动正式发布中国首个AI原生集成开发环境工具(AI IDE)——AI编程工具Trae国内版。 该工具模型搭载doubao-1.5-pro,支持切换满血版DeepSeek R1&V3, 可以帮助各阶段开发者与AI流畅协作,更快、更高质量地完…...
第11章 web应用程序安全(网络安全防御实战--蓝军武器库)
网络安全防御实战--蓝军武器库是2020年出版的,已经过去3年时间了,最近利用闲暇时间,抓紧吸收,总的来说,第11章开始学习利用web应用程序安全,主要讲信息收集、dns以及burpsuite,现在的资产测绘也…...
MySQL复习笔记
MySQL复习笔记 1.MySQL 1.1什么是数据库 数据库(DB, DataBase) 概念:数据仓库,软件,安装在操作系统(window、linux、mac…)之上 作用:存储数据,管理数据 1.2 数据库分类 关系型数据库&#…...
GitHub上传项目
总结(有基础的话直接执行这几步,就不需要再往下看了): git init 修改git的config文件:添加:[user]:name你的github用户名 email你注册github的用户名 git branch -m master main git remote add origin 你的URL gi…...
自我训练模型:通往未来的必经之路?
摘要 在探讨是否唯有通过自我训练模型才能掌握未来的问题时,文章强调了底层技术的重要性。当前,许多人倾向于关注应用层的便捷性,却忽视了支撑这一切的根本——底层技术。将模型简单视为产品是一种短视行为,长远来看,理…...
qt 操作多个sqlite文件
qt 操作多个sqlite文件 Chapter1 qt 操作多个sqlite文件1. 引入必要的头文件2. 创建并连接多个SQLite数据库3. 代码说明4. 注意事项 Chapter2 qt 多线程操作sqlite多文件1. 引入必要的头文件2. 创建数据库操作的工作线程类3. 在主线程中创建并启动多个工作线程4. 代码说明5. 运…...
【每日学点HarmonyOS Next知识】多继承、swiper容器、事件传递、滚动安全区域、提前加载网络图片
1、HarmonyOS ArkTS如何让一个类可以具备其他多个类的能力? ArkTS如何让一个类可以具备其他多个类的能力,类似于多继承。 接口支持多继承。类不支持,其只支持单继承。 (报错:Classes can only extend a single class…...
DIY Tomcat:手写一个简易Servlet容器
在Java Web开发领域,Tomcat堪称经典,它作为Servlet容器,承载着无数Web应用的运行。今天,我将带大家一同探索如何手写一个简易的Tomcat,深入理解其底层原理。 一、背景知识 在开始之前,我们需要对几个关键…...
如何在Ubuntu上直接编译Apache Doris
以下是在 Ubuntu 22.04 上直接编译 Apache Doris 的完整流程,综合多个版本和环境的最佳实践: 注意:Ubuntu的数据盘VMware默认是20G,编译不够用,给到50G以上吧 一、环境准备 1. 安装系统依赖 # 基础构建工具链 apt i…...
基于ssm的物资进销存(全套)
现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本货物进销管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息&#…...
【CVPR2025】 EVSSM:用状态空间模型高效去模糊
Efficient Visual State Space Model for Image Deblurring 论文信息 题目: Efficient Visual State Space Model for Image Deblurring 用于图像去模糊的高效视觉状态空间模型 源码:https://github.com/kkkls/EVSSM 创新点 提出了高效视觉状态空间模型…...
动态规划--斐波那契类型
目录 前言 1 第N个斐波那契数 2 爬楼梯 3 三步问题 4 使用最小花费爬楼梯 5 解码方法 总结 前言 本篇所讲的几个题目都是与斐波那契数的做法与思路类似的题目,所以直接放在一块解决了。 同时,由于第一次接触动态规划,我们也会讲解一…...
supervisord管理Gunicorn进程,使用Nginx作为反向代理运行flask web项目
1. 安装 Gunicorn 在项目虚拟环境中安装 Gunicorn:2. 基本用法 配置文件 创建一个 Gunicorn 配置文件(如 gunicorn_config.py),方便管理复杂配置。 示例 gunicorn_config.py: bind "0.0.0.0:8000" #…...
《Python实战进阶》No16: Plotly 交互式图表制作指南
No16: Plotly 交互式图表制作指南 Plotly是一款用来做数据分析和可视化的在线平台,功能真的是非常强大,它主要有以下特点: 图形多样化:在线绘制多种图形,比如柱状图、饼图、直方图、饼图、气泡图、桑基图、股票图、旭…...
代码随想录算法训练营第22天 | 组合总和 分割回文串
39. 组合总和 39. 组合总和 - 力扣(LeetCode) 题目链接/文章讲解:代码随想录 视频讲解:带你学透回溯算法-组合总和(对应「leetcode」力扣题目:39.组合总和)| 回溯法精讲!_哔哩哔哩_…...
DeepSeek 医疗大模型微调实战讨论版(第一部分)
DeepSeek医疗大模型微调实战指南第一部分 DeepSeek 作为一款具有独特优势的大模型,在医疗领域展现出了巨大的应用潜力。它采用了先进的混合专家架构(MoE),能够根据输入数据的特性选择性激活部分专家,避免了不必要的计算,极大地提高了计算效率和模型精度 。这种架构使得 …...
