Qt (19)【Qt 线程安全 | 互斥锁QMutex QMutexLocker | 条件变量 | 信号量】
阅读导航
- 引言
- 一、互斥锁
- 1. QMutex
- (1)基本概念
- (2)使用示例
- 基本需求
- ⭕thread.h
- ⭕thread.cpp
- ⭕widget.h
- ⭕widget.cpp
- 2. QMutexLocker
- (1)基本概念
- (2)使用示例
- 3. QReadWriteLocker、QReadLocker、QWriteLocker
- (1)基本概念
- (2)使用示例
- 二、条件变量
- 1. 基本概念
- 2. 使用示例
- 三、信号量
- 1. 基本概念
- 2. 使用示例
引言
在Qt中,为了构建高效且安全的多线程应用程序,我们需要关注线程安全问题。Qt提供了几种关键的同步机制,包括互斥锁(QMutex)及其自动管理助手QMutexLocker,用于确保资源互斥访问;条件变量,用于线程间的协调与等待/唤醒机制;以及信号量,用于控制对资源的并发访问数。这些工具共同协作,帮助开发者避免数据竞争和死锁,实现线程间的安全交互。
(PS:Linux有详细讲过这方面的知识,传送门:💻【探索Linux】P.21多线程 | 线程同步 | 条件变量 | 线程安全)
一、互斥锁
⭕互斥锁是⼀种保护和防止多个线程同时访问同⼀对象实例的方法,在Qt中,互斥锁主要是通过QMutex类来处理。
1. QMutex
(1)基本概念
QMutex 是 Qt 框架中一个重要的类,它实现了互斥锁的功能。主要用途是在多线程程序中保护对共享资源的访问,通过锁定和解锁机制来确保同一时间只有一个线程能够访问特定的数据或执行某段代码,从而避免数据竞争和不一致的问题,实现线程间的互斥操作,保证程序的线程安全性。
(2)使用示例
基本需求
使用两个线程对同一个全局变量进行加加,每个线程加5000次
⭕thread.h
#ifndef THREAD_H
#define THREAD_H#include <QWidget>
#include <QThread>
#include <QMutex>class Thread : public QThread
{Q_OBJECT
public:Thread();// 添加一个 static 成员.static int num;// 创建锁对象static QMutex mutex;void run();
};#endif // THREAD_H
⭕thread.cpp
#include "thread.h"
#include <QMutexLocker>int Thread::num = 0;QMutex Thread::mutex;Thread::Thread()
{
}void Thread::run()
{for (int i = 0; i < 50000; i++) {mutex.lock();num++;mutex.unlock();}
}
⭕widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;
};
#endif // WIDGET_H
⭕widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "thread.h"
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 创建两个线程对象.Thread t1;Thread t2;t1.start();t2.start();// 加上线程的等待, 让主线程等待这俩线程执行结束.t1.wait();t2.wait();// 打印结果.qDebug() << Thread::num;
}Widget::~Widget()
{delete ui;
}
2. QMutexLocker
(1)基本概念
QMutexLocker 是 QMutex 的一个辅助类,它采用了资源获取即初始化(RAII, Resource Acquisition Is Initialization)的设计模式。这一模式确保了互斥锁(QMutex)在 QMutexLocker 对象的生命周期内被自动上锁,并在该对象被销毁时自动解锁。通过这种方式,QMutexLocker 极大地简化了对互斥锁的管理,开发者无需手动调用上锁(lock)和解锁(unlock)函数,从而避免了因忘记解锁而导致的死锁等潜在问题。
(2)使用示例

上面的QMutex的示例代码只用进行图片中的变换就可以使用QMutexLocker了。
3. QReadWriteLocker、QReadLocker、QWriteLocker
(1)基本概念
QReadWriteLock 是一个读写锁类,它设计用于精细控制对共享资源的并发访问权限,特别是在处理读写操作时。在这个锁机制中,区分了读操作和写操作的不同需求。
-
QReadLocker是用于读操作的上锁工具。当多个线程需要同时读取共享资源时,QReadLocker允许这些线程同时获得读锁,从而并行访问资源。这种方式提高了读取操作的并发效率,因为读取通常不会修改数据,因此多个读者可以同时安全地访问资源。 -
QWriteLocker则是用于写操作的上锁工具。与读操作不同,写操作会修改共享资源,因此QWriteLocker确保在任何给定时间内,只有一个线程能够持有写锁,从而独占对共享资源的写入权限。这保证了数据的一致性和完整性,避免了并发写入可能导致的冲突。
(2)使用示例
QReadWriteLock rwLock;//在读操作中使⽤读锁{QReadLocker locker(&rwLock); //在作⽤域内⾃动上读锁//读取共享资源//...} //在作⽤域结束时⾃动解读锁//在写操作中使⽤写锁{QWriteLocker locker(&rwLock); //在作⽤域内⾃动上写锁//修改共享资源//...} //在作⽤域结束时⾃动解写锁
二、条件变量
1. 基本概念
在多线程编程中,有时线程需要等待某个条件成立才能继续执行。Qt提供了QWaitCondition类来处理这种情况。QWaitCondition允许线程在条件不满足时暂停(等待),并在条件满足时被其他线程唤醒。这样,线程可以基于条件进行同步和协调,而不仅仅是简单地轮流使用资源。
2. 使用示例
QMutex mutex;
QWaitCondition condition;//在等待线程中
mutex.lock();//检查条件是否满⾜,若不满⾜则等待while (!conditionFullfilled())
{condition.wait(&mutex); //等待条件满⾜并释放锁
}//条件满⾜后继续执⾏
//...mutex.unlock();//在改变条件的线程中
mutex.lock();//改变条件
changeCondition();
condition.wakeAll(); //唤醒等待的线程mutex.unlock();
三、信号量
1. 基本概念
在多线程编程中,如果多个线程需要访问有限的资源(如内存),就需要控制同时访问这些资源的线程数量。Qt中的QSemaphore就是一个工具,它可以限制同时运行的线程数,从而管理资源的使用。简单来说,QSemaphore就像一个计数器,用于确保不会有太多线程同时占用资源。
2. 使用示例
QSemaphore semaphore(2); //同时允许两个线程访问共享资源//在需要访问共享资源的线程中
semaphore.acquire(); //尝试获取信号量,若已满则阻塞//访问共享资源
//...semaphore.release(); //释放信号量//在另⼀个线程中进⾏类似操作
相关文章:
Qt (19)【Qt 线程安全 | 互斥锁QMutex QMutexLocker | 条件变量 | 信号量】
阅读导航 引言一、互斥锁1. QMutex(1)基本概念(2)使用示例基本需求⭕thread.h⭕thread.cpp⭕widget.h⭕widget.cpp 2. QMutexLocker(1)基本概念(2)使用示例 3. QReadWriteLocker、QR…...
Java语法-类和对象(上)
1. 面向对象的初步认识 1.1 什么是面向对象 概念: Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。 1.2 面向对象VS面向过程 如:洗衣服 面向过程: 注重的是洗衣服的过程,少了一个环节也不…...
Presto如何配置资源队列或资源组
Presto的任务队列配置主要涉及到查询队列和资源组的配置,这些配置通常用于管理Presto集群中的查询执行和资源分配。但是注意这两个东西是共存,互补的关系,并不需要纠结那种配置方式更加出色 一、查询队列配置 Presto的查询队列配置主要通过…...
828华为云征文|使用Flexus X实例集成ES搜索引擎
目录 一、应用场景 1.1 Flexus X实例概述 1.2 ES搜索引擎 二、安装相关服务 2.1 安装Elasticsearch7.17.0 2.2 安装kibana7.17.0 三、开通安全组规则 四、整体感受 4.1 Flexus X实例 4.2 使用感觉 一、应用场景 1.1 Flexus X实例概述 Flexus X实例是华为云推出的一款…...
【设计模式-访问者模式】
定义 访问者模式(Visitor Pattern)是一种行为型设计模式,允许你在不修改已有类的情况下向这些类添加新的功能或行为。它通过将操作的执行逻辑从对象的类中分离出来,使得你可以在保持类的封闭性(符合开闭原则ÿ…...
一元运算符(自增自减)
一、一元运算符 一元运算符,只需要一个操作数 1. 正号 正号不会对数字产生任何影响 2.-负号 负号可以对数字进行负号的取反 对于非Number的值,会将先转换为Number,在进行运算: 可以对一个其他的数据类型使用,来将其转换为n…...
gitlab/极狐-离线包下载地址
如果想要使用Gitlab/极狐进行数据的恢复,只能使用相同版本或者相近版本的安装包,因此有时候需要到它的官网上下载对应版本的安装包,以下是我收集到的对应地址的下载路径: Gitlab Gitlab离线库, https://packages.gitl…...
C++——输入三个整数,按照由小到大的顺序输出。用指针方法处理。
没注释的源代码 #include <iostream> using namespace std; void swap(int *m,int *n); int main() { int a,b,c; int *p1,*p2,*p3; cout<<"请输入三个整数:"<<endl; cin>>a>>b>>c; p1&a;p2&b;p3&c;…...
【Java8 重要特性】Lambda 表达式
文章目录 Lambda函数式接口Lambda 规则规范简化过程改写 Arrays.setAll()改写 Arrays.sort() forEach循环 list 集合循环 list 集合并输出对象信息循环 Map 集合 方法引用和构造器引用方法引用构造器引用 Lambda Lambda是一个匿名函数,我们可以将Lambda表达式理解为…...
word2vec--CBOW与Skip-Gram 两种模型
Word2Vec 是一种流行的用于生成词嵌入(Word Embeddings)的无监督学习模型,它由 Google 的一个团队在 2013 年提出。它的主要目的是将单词映射到一个连续的向量空间,使得语义相似的单词在这个空间中靠得更近。 Word2Vec 有两种主要…...
iOS六大设计原则设计模式
六大设计原则: 一、单一职责原则 一个类或者模块只负责完成一个职责或者功能。 类似于:UIView 和 CALayer 二、开放封闭原则 对扩展开放,对修改封闭。 我们要尽量通过扩展软件实体来解决需求变化,而不是通过修改已有的代码来…...
nacos 集群搭建
主机准备 IProle192.168.142.155slave02192.168.142.156slave192.168.142.157master 三台主机上分别构建 mysql 镜像 FROM mysql:8.0.31 ADD https://raw.githubusercontent.com/alibaba/nacos/develop/distribution/conf/mysql-schema.sql /docker-entrypoint-initdb.d/nac…...
STM32快速复习(十二)FLASH闪存的读写
文章目录 一、FLASH是什么?FLASH的结构?二、使用步骤1.标准库函数2.示例函数 总结 一、FLASH是什么?FLASH的结构? 1、FLASH简介 (1)STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分&…...
漏洞扫描工具使用
首先把补丁的两个文件复制下来替换原文件 找到C:\ProgramData\Acunetix\shared\license然后替换 然后打开漏扫工具并刷新页面 然后添加要扫描的网站 等他扫描完成 扫描完成就可以生成报告了 一共五十多页的报告...
C++ | Leetcode C++题解之第424题替换后的最长重复字符
题目: 题解: class Solution { public:int characterReplacement(string s, int k) {vector<int> num(26);int n s.length();int maxn 0;int left 0, right 0;while (right < n) {num[s[right] - A];maxn max(maxn, num[s[right] - A]);i…...
利士策分享,动摇时刻的自我救赎
利士策分享,动摇时刻的自我救赎 在人生的长河中,我们每个人都会面临各种挑战与抉择, 那些让人心生动摇的瞬间,如同夜空中偶尔掠过的乌云,遮蔽了前行的星光。 但正是这些动摇,构成了我们成长的轨迹&#x…...
动手学深度学习(李沐)PyTorch 第 1 章 引言
在线电子书 深度学习介绍 安装 使用conda环境 conda create -n d2l-zh python3.8 pip安装需要的包 pip install jupyter d2l torch torchvision下载代码并执行 wget https://zh-v2.d2l.ai/d2l-zh.zip unzip d2l-zh.zip jupyter notebookpip install rise如果不想使用jupyt…...
二叉树(二)深度遍历和广度遍历
一、层序遍历 广度优先搜索:使用队列,先进先出 模板: 1、定义返回的result和用于辅助的队列 2、队列初始化: root非空时进队 3、遍历整个队列:大循环while(!que.empty()) 记录每层的size以及装每层结果的变量&a…...
【算法——双指针】
922. 按奇偶排序数组 II 算法讲解050【必备】双指针技巧与相关题目_哔哩哔哩_bilibili main:vector<int>nums { 3,1,2,4 };int i 0, j 1;int n nums.size() - 1;while (j < nums.size() && i < nums.size()) //如果奇偶任一方排好了,另…...
Rocky Linux 9 中添加或删除某个网卡的静态路由的方法
使用ip命令配置临时路由 添加静态路由 ip route add <目的网络> via <下一跳IP> dev <网卡接口名称>例: 给eth0网卡添加一个到达 192.168.2.0/24 网络,下一跳为 192.168.1.254 的路由 ip route add 192.168.2.0/24 via 192.168.1.254 dev eth0…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...
动态规划-1035.不相交的线-力扣(LeetCode)
一、题目解析 光看题目要求和例图,感觉这题好麻烦,直线不能相交啊,每个数字只属于一条连线啊等等,但我们结合题目所给的信息和例图的内容,这不就是最长公共子序列吗?,我们把最长公共子序列连线起…...
