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…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
