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)基本概念

QMutexLockerQMutex 的一个辅助类,它采用了资源获取即初始化(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(); //释放信号量//在另⼀个线程中进⾏类似操作

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】简易日志系统

目录 一、概念 二、可变参数 三、日志系统 一、概念 一个正在运行的程序或系统就像一个哑巴&#xff0c;一旦开始运行我们很难知晓其内部的运行状态。 但有时在程序运行过程中&#xff0c;我们想知道其内部不同时刻的运行结果如何&#xff0c;这时一个日志系统可以有效的帮…

软考无损连接判断

如何判断是否为无损连接&#xff0c;要看能否还原回最开始的关系模式 最开始的关系模式 U{A&#xff0c;B&#xff0c;C} 函数连接 F{A -> B}&#xff0c;这个函数连接的意思就是A可以推导出B 首先从P1开始判断&#xff0c;{ AB&#xff0c;BC } C不能通过函数依赖推导出来…

数据结构之线性表——LeetCode:328. 奇偶链表,86. 分隔链表,24. 两两交换链表中的节点

328. 奇偶链表 题目描述 328. 奇偶链表 给定单链表的头节点 head &#xff0c;将所有索引为奇数的节点和索引为偶数的节点分别组合在一起&#xff0c;然后返回重新排序的列表。 第一个节点的索引被认为是 奇数 &#xff0c; 第二个节点的索引为 偶数 &#xff0c;以此类推。…

头条|司法部公法局局长访谈:推进高水平公立鉴定机构建设!加快推进司法鉴定立法!

主持人&#xff1a;大家好&#xff0c;我是司法部AI主播司政轩。为切实做好党的二十届三中全会精神学习宣传贯彻&#xff0c;积极反映司法部及地方司法行政机关学习全会精神的体会收获和贯彻落实举措&#xff0c;我们推出了“学习宣传贯彻党的二十届三中全会精神--司法行政微访…

Elasticsearch 检索优化:停用词的应用

Elasticsearch 检索优化&#xff1a;停用词的应用 场景描述 目前在 Elasticsearch 集群中存储约 1.5 亿篇文章数据&#xff0c;随着数据量的增加&#xff0c;检索性能问题逐渐显现。在列表检索和聚合操作中&#xff0c;CPU 消耗飙升至 100%&#xff0c;并且检索耗时较长&…

私域电商:自主发展新路径与创新模式融合

摘要&#xff1a;本文深入探讨了私域电商相较于传统电商在自主权方面的优势&#xff0c;并结合 AI 智能名片、链动 21 模式以及商城小程序等创新元素&#xff0c;阐述了私域电商如何为商家提供更大的发展空间和自主权&#xff0c;以及这些创新模式在私域电商中的应用价值&#…

口碑最好的头戴式耳机是哪些?高品质头戴式耳机对比测评揭晓

头戴式耳机以其出色的音质表现和舒适的佩戴体验&#xff0c;成为了音乐爱好者和日常通勤用户的热门选择。而在众多品牌和型号中&#xff0c;口碑最好的头戴式耳机是哪些&#xff1f;面对市场上丰富的选择&#xff0c;找到一款音质优良、佩戴舒适且性价比高的耳机并不容易。今天…

ESP8266+DHT11+Python制作一个物联网温湿度传感器

ESP8266是一款低功耗、高集成度的Wi-Fi SOC&#xff08;System on Chip&#xff0c;系统级芯片&#xff09;&#xff0c;这款芯片专为物联网&#xff08;IoT&#xff09;应用而设计&#xff0c;常见开发ESP8266的环境可以使用Arduino或者ESP8266 RTOS SDK、NodeMCU&#xff0c;…

【JavaScript】数据结构之链表(双指针、滑动窗口)

什么是链表&#xff1f; 多个元素存储的列表链表中的元素在内存中不是顺序存储的&#xff0c;而是通过“next”指针联系在一起的&#xff0c;这个“next”可以自定义。JS中的原型链原理就是链表结构&#xff0c;是通过__proto__指针联系在一起的。 双指针形式 对撞指针&am…

你还在为试衣间排队烦恼吗?AI魔法绘,让虚拟试衣触手可及!

我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 大家好&#xff01;今天我要跟大家聊聊一个超级有趣又实用的新…

施耐德EcoStruxure Machine SCADA Expert(EMSE)报警记录进阶(十六)

针对某些特殊行业&#xff08;诸如医药行业&#xff09;的设备生产需要符合GMP相关规定&#xff0c;这就导致需要数据溯源。 EMSE可以通过与sql的连接实现报警历史记录的永久存储。 1.EMSE打开相关配置 2.sql创建表单 用于报警历史数据的存储容器 3.EMSE内选择sql表单 4.现在…

mistune,一个神奇的 Python 库!

大家好&#xff0c;今天为大家分享一个神奇的 Python 库 - mistune。 Github地址&#xff1a;https://github.com/lepture/mistune Markdown 是一种轻量级的标记语言&#xff0c;以其简洁的语法和可读性广泛应用于文档编写、博客发布和在线内容管理系统中。Python 作为一门灵活…

【ESP32】ESP-IDF开发 | UART通用异步收发传输器+串口收发例程

1. 简介 UART可以说是开发者使用得最多的外设之一了&#xff0c;打印log几乎都是使用串口来实现的。UART是一种异步全双工的通信方式&#xff0c;异步传输的特性使得它仅需2根线就可以完成全双工的传输&#xff0c;但这也要求发送端和接收端的速率、停止位、奇偶校验位等都要相…

分布式计算技术是什么?在数据集成值得作用?

数据是现代科技技术的基础&#xff0c;面对爆炸性数据的增长&#xff0c;要求计算能力要求更高、数据整合和处理更有效&#xff0c;如何应对数据集成带来的挑战&#xff1f;本文将探讨分布式计算技术在数据集成中的优化作用。 一 分布式计算技术。 定义&#xff1a;分布式计算…

笔记:将WPF中可视化元素(Visual)保存为图像,如PNG,JPEG或BMP的方法简介

一、目的&#xff1a;将WPF中可视化元素&#xff08;Visual&#xff09;保存为图像&#xff0c;如PNG,JPEG或BMP的方法简介 BitmapEncoder 是 WPF 中用于将图像数据编码为特定格式的基类。它提供了将 BitmapSource 对象保存为各种图像格式&#xff08;如 PNG、JPEG、BMP 等&…

Android Choreographer 监控应用 FPS

Choreographer 是 Android 提供的一个强大的工具类&#xff0c;用于协调动画、绘制和视图更新的时间。它的主要作用是协调应用的绘制过程&#xff0c;以确保流畅的用户体验。Choreographer 也可以帮助我们获取帧时间信息&#xff0c;从而为性能监测和优化提供重要的数据支持。 …

C++—vector的常见接口与用法(正式进入STL)

目录 0.提醒 1.介绍 2.构造 1.正常构造 2.默认值构造 3.调用默认构造函数构造 3.遍历 1.迭代器 2.范围for 3.下标访问 4.容量 1.capacity&#xff1a;返回当前容器的容量 2.reserve&#xff1a;如果传的k比当前容量大&#xff0c;则扩容到比k大或者等于k的数&…

车载软件调试工具系列---Trace32简介UI界面简介

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

二叉搜索树的使用及其详细解析

1.概念 ⼆叉搜索树⼜称⼆叉排序树&#xff0c;它或者是⼀棵空树&#xff0c;或者是具有以下性质的⼆叉树: • 若它的左⼦树不为空&#xff0c;则左⼦树上所有结点的值都⼩于等于根结点的值 • 若它的右⼦树不为空&#xff0c;则右⼦树上所有结点的值都⼤于等于根结点的值 • 它…

JDK如何下载源码?

文章目录 JDK如何下载源码&#xff1f;JDK源码介绍下载JDK源码idea配置源码路径 JDK如何下载源码&#xff1f; JDK&#xff08;Java Development Kit&#xff09;是开发Java应用程序的基础工具包&#xff0c;包含了编译、运行和调试Java应用程序所需的所有工具。JDK源码主要指…