【QT5 多线程示例】互斥锁
互斥锁
互斥锁介绍:【C++并发编程】(三)互斥锁:std::mutex。原理都一样,这里就不赘述了。
QMutex 是 Qt 框架中提供的一个互斥锁类,主要包括以下成员函数:
- lock():试图锁定互斥量。如果另一个线程已经锁定了这个互斥量,调用线程将被阻塞,直到那个线程解锁。
- unlock():解锁互斥量,允许其他线程锁定它。
- tryLock():尝试锁定互斥量,不阻塞调用线程。如果互斥量被锁定,函数返回
false;如果成功锁定,返回true。 - tryLock(int timeout):尝试在指定的毫秒数内锁定互斥量。如果超时仍未锁定,返回
false;如果成功锁定,返回true。 - locked():查询互斥量当前是否被锁定。如果被锁定,返回
true;否则返回false。
在简单的函数中,可以直接使用 QMutex 的 lock() 和 unlock() 成员函数。但在复杂的函数中,使用 QMutexLocker 自动管理互斥锁更为安全和方便。QMutexLocker 与C++标准中std::lock_guard的用法差不多,而且也是基于 RAII(Resource Acquisition Is Initialization)机制的,在构造时自动锁定互斥量,在析构时自动解锁。
下面给出示例代码:
https://github.com/BinaryAI-1024/QtStudy/tree/master/thread/mutex
//myworker.h
#ifndef MYWORKER_H
#define MYWORKER_H#include <QObject>
#include <QMutex>
#include <QDebug>class MyWorker : public QObject
{Q_OBJECT
signals:void finished();public:explicit MyWorker(QObject *parent = nullptr);// 获取 counter 的值static int getCounter();public slots:void doWork(int id);private:static QMutex mutex;static int counter;
};#endif // MYWORKER_H
//myworker.cpp
#include "myworker.h"// 静态成员初始化
QMutex MyWorker::mutex;
int MyWorker::counter = 0;MyWorker::MyWorker(QObject *parent): QObject(parent)
{
}void MyWorker::doWork(int id)
{qDebug() << "Worker" << id << "started work.";for (int i = 0; i < 100000; ++i) {QMutexLocker locker(&mutex); // // 加锁以保护数据++counter;}emit finished(); // 发送完成信号
}int MyWorker::getCounter()
{return counter;
}
//main.cpp
#include <QCoreApplication>
#include <QThread>
#include "myworker.h"
#include <QTimer>
#include <QMutex>
#include <QMutexLocker>int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);QMutex mutex; // 创建一个互斥锁const int numThreads = 3; // 定义要启动的线程数量QThread *threads[numThreads]; // 创建一个 QThread 指针数组,用于存储线程对象MyWorker *workers[numThreads]; // 创建一个 MyWorker 指针数组,用于存储工作对象int finishedCount = 0; // 初始化一个计数器,用于跟踪完成的线程数量// 循环创建和启动线程for (int i = 0; i < numThreads; ++i) {threads[i] = new QThread; // 创建一个新线程workers[i] = new MyWorker; // 创建一个新工作对象workers[i]->moveToThread(threads[i]); // 将工作对象移动到新线程中// 连接线程的 started 信号到工作对象的 doWork 槽,使用 QTimer 确保在事件循环开始后执行QObject::connect(threads[i], &QThread::started, workers[i], [=]() {QTimer::singleShot(0, workers[i], [=]() { workers[i]->doWork(i); });});// 连接工作对象的 finished 信号到线程的 quit 槽,以便任务完成后退出线程的事件循环QObject::connect(workers[i], &MyWorker::finished, threads[i], &QThread::quit);// 连接工作对象的 finished 信号到工作对象的 deleteLater 槽,以便任务完成后删除工作对象QObject::connect(workers[i], &MyWorker::finished, workers[i], &QObject::deleteLater);// 连接线程的 finished 信号到线程的 deleteLater 槽,以便线程退出后删除线程对象QObject::connect(threads[i], &QThread::finished, threads[i], &QObject::deleteLater);// 连接工作对象的 finished 信号到一个 lambda 表达式,用于更新计数器并检查所有线程是否完成QObject::connect(workers[i], &MyWorker::finished, [&finishedCount, &mutex, i]() {QMutexLocker locker(&mutex); // 加锁以保护计数器的访问++finishedCount; // 增加已完成线程的计数qDebug() << "Worker" << i << "finished. " ;if (finishedCount == numThreads) { // 检查是否所有线程都已完成// 每个线程使counter增加100000,正确结果应该是:numThreads*100000qDebug() << "counter:" << MyWorker::getCounter();}});threads[i]->start(); // 启动线程}return app.exec();
}
结果:
Worker 1 started work.
Worker 0 started work.
Worker 2 started work.
Worker 1 finished.
Worker 2 finished.
Worker 0 finished.
counter: 300000
互斥锁在代码中保护了main.cpp中的 ++finishedCount;以及mythread.cpp中的++counter;,避免了多个线程同时执行这些操作导致的错误。QMutexLocker能够自动管理局部作用域内互斥锁的加锁和开锁。
另外,在这段代码中,不需要调用 thread.wait() 是因为 Qt 的信号和槽机制自动管理了线程的生命周期。通过 QThread::quit() 和 QObject::deleteLater(),线程在任务完成后自动退出并清理资源。
相关文章:
【QT5 多线程示例】互斥锁
互斥锁 互斥锁介绍:【C并发编程】(三)互斥锁:std::mutex。原理都一样,这里就不赘述了。 QMutex 是 Qt 框架中提供的一个互斥锁类,主要包括以下成员函数: lock():试图锁定互斥量。…...
SaaS系统的销售微服务与权限微服务边界设计
在设计SaaS系统的销售微服务与权限微服务的边界时,需要结合领域驱动设计(DDD)和微服务拆分原则,确保高内聚、低耦合。以下是结合微服务架构原则、多租户SaaS需求及权限管理场景的完整设计方案,整合了权限服务与销售服务…...
leetcode热题100道——两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。 你可以按任意顺序返回答案。 示例 1…...
C语言经典代码练习题
1.输入一个4位数:输出这个输的个位 十位 百位 千位 #include <stdio.h> int main(int argc, char const *argv[]) {int a;printf("输入一个4位数:");scanf("%d",&a);printf("个位:%d\n"…...
Git远程拉取和推送配置
Git进行远程代码拉取和推送时候提示配置user.name 和 user.email 背景:换新电脑后使用Git进行代码拉取和推送过程中,提示“Make sure you configure your “user.name” and “user.email” in git.”。这个配置针对git的正常使用仅需要配置一次…...
MySQL WHERE 子句详解
MySQL WHERE 子句详解 引言 在数据库操作中,WHERE 子句是用于筛选记录的重要工具。它允许我们在查询中指定条件,从而只选择满足特定条件的记录。本文将详细介绍 MySQL 中的 WHERE 子句,包括其语法、用法以及一些高级技巧。 WHERE 子句的基…...
基于SpringBoot+Vue3实现的宠物领养管理平台功能七
一、前言介绍: 1.1 项目摘要 随着社会经济的发展和人们生活水平的提高,越来越多的人开始关注并参与到宠物领养中。宠物已经成为许多家庭的重要成员,人们对于宠物的关爱和照顾也日益增加。然而,传统的宠物领养流程存在诸多不便&a…...
【leetcode hot 100 994】腐烂的橘子
多源广度优先搜索 所有的腐烂橘子在广度优先搜索上是等价于同一层的节点的。假设这些腐烂橘子刚开始是新鲜的,而有一个腐烂橘子(我们令其为超级源点)会在下一秒把这些橘子都变腐烂,而这个腐烂橘子刚开始在的时间是 −1,那么按照广度优先搜索…...
精挑20题:MySQL 8.0高频面试题深度解析——掌握核心知识点、新特性和优化技巧
1. MySQL 8.0 中,为什么查询缓存被移除? 答案: 原因:查询缓存对频繁更新的表效果差,任何对该表的写操作都会清空所有相关缓存,导致缓存命中率低,反而增加开销。 替代方案: 使用应用…...
调研报告:Hadoop 3.x Ozone 全景解析
Ozone 是 Hadoop 的分布式对象存储系统,具有易扩展和冗余存储的特点。 Ozone 不仅能存储数十亿个不同大小的对象,还支持在容器化环境(比如 Kubernetes)中运行。 Apache Spark、Hive 和 YARN 等应用无需任何修改即可使用 Ozone。Ozone 提供了 Java API、S3 接口和命令行接口…...
深入理解 RLP 编码与 JSON:原理、应用与比较
在区块链和数据存储领域,RLP(Recursive Length Prefix)编码和**JSON(JavaScript Object Notation)**是两种重要的数据编码方式。它们分别适用于不同的应用场景,并具有不同的优缺点。本文将系统性地分析 RLP…...
【Linux】Makefile秘籍
> 🍃 本系列为Linux的内容,如果感兴趣,欢迎订阅🚩 > 🎊个人主页:【小编的个人主页】 >小编将在这里分享学习Linux的心路历程✨和知识分享🔍 >如果本篇文章有问题,还请多多包涵&a…...
玩转物联网-4G模块如何快速将数据上传到巴法云(TCP篇)
目录 1 前言 2 环境搭建 2.1 硬件准备 2.2 软件准备 2.3 硬件连接 2.4 检查驱动 3 巴法云平台设备创建 3.1 创建账号 3.2 进入巴法云 3.3 获取联网参数 4 连接巴法云 4.1 打开配置工具读取基本信息 4.2 设置连接参数进行数据交互 4.2.1 建立TCP连接 4.2.2 订阅主题 4.2.3 发布信…...
postgresql 高版本pgsql备份在低版本pgsql中恢复失败,报错:“unsupported version”
关键字 PostgreSQL、pg_restore、版本兼容性、数据库迁移、pg_dump、备份恢复、unsupported version in file header 背景环境 系统配置 环境类型操作系统PostgreSQL版本内存工具链测试环境Windows 111616GBNavicat/PgAdmin生产环境Windows Server 2012 R2128GBPgAdmin/命令…...
html相关常用语法
html相关常用语法 HTML(HyperText Markup Language)即超文本标记语言,是用于创建网页的标准标记语言 HTML使用标记语言描述Web页面的结构 HTML元素是HTML页面的建构快 HTML元素通过标签tag来表示 HTML标签是“标题”、”段落“、”表格“等内…...
vue3+ts心得
1、Vue3核心 1、setup setup里弱化this,return可以返回函数,返回后页面也显示那个函数值 data里面是可以用this.来获取setup里的值,这个是单向的 vue3两个script标签不要觉得奇怪,一个是配置组合式api的,一个是配置组…...
单片机flash存储也做磨损均衡
最近在做一个项目,需要保存设置数据,掉电不丢失。那么首先想到的是加个24c02,是一个eeprom,但是客户板太小,没有办法进行扩展。后面就找了一个带ee的OTP单片机,发现擦写次数有限,只有1000次&…...
【FAQ】HarmonyOS SDK 闭源开放能力 —Push Kit(10)
1.问题描述: 离线推送,锁屏的时候没有弹出消息,只有下拉在通知中心里面显示。请问是否是正常的? 解决方案: 检查一下是否存在图片风控:https://developer.huawei.com/consumer/cn/doc/harmonyos-referen…...
SQLark中如何进行数据筛选与排序
本文将为你介绍在 SQLark 中如何进行数据筛选与排序,掌握这些操作能够极大提升你的工作效率。 SQLark官网链接:www.sqlark.com 数据筛选 在数据库操作中,数据筛选是一项关键功能,它依据特定条件对数据进行过滤,帮助用户从海量数据…...
token升级(考虑在分布式环境中布置token,结合session保证请求调用过程中token不会过期。)
思路: 首先,用户的需求是确保使用同一个Token的外部调用都在一个Session中处理。 需要考虑Token与Session绑定、安全措施、Session管理、分布式处理等。 使用Redis作为Session存储, 在Java中 通过Spring Data Redis或Lettuce库实现。 2.生成…...
VSTO(C#)Excel开发11:自定义任务窗格与多个工作簿
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...
python:AI+ music21 构建LSTM模型生成爵士风格音乐
这是一个使用 python的 music21 和 TensorFlow/Keras 构建 LSTM 模型生成爵士风格音乐的完整脚本。该脚本包含MIDI数据处理、模型训练和音乐生成全流程: # -*- coding: utf-8 -*- """AI music21 和 TensorFlow/Keras 构建LSTM模型生成爵士风格音乐 …...
vscode查看文件历史git commit记录
方案一:GitLens 在vscode扩展商店下载GitLens 选中要查看的文件,vscode界面右上角点击GitLens的图标,选择Toggle File Blame 界面显示当前打开文件的所有修改历史记录 鼠标放到某条记录上,可以看到记录详情,选中O…...
使用netDxf扩充LaserGRBL使它支持Dxf文件格式
为 LaserGRBL 扩展支持 DXF 文件格式,需要了解 LaserGRBL 的代码结构,并在其基础上添加 DXF 文件的解析和转换逻辑。以下是详细的扩展方案: 1. 了解 LaserGRBL LaserGRBL 是一个用于控制激光雕刻机的开源软件,支持 G 代码文件的加…...
GaussDB备份数据常用命令
1、常用备份命令gs_dump 说明:是一个服务器端工具,可以在线导出数据库的数据,这些数据包含整个数据库或数据库中指定的对象(如:模式,表,视图等),并且支持导出完整一致的数…...
数学建模 第三节
目录 前言 一 钻井布局问题 第一问分析 第二问分析 总结 前言 这里讲述99年的钻井布局问题,利用这个问题讲述模型优化,LINGO,MATLAB的使用 一 钻井布局问题 这个是钻井布局的原题,坐标的位置为 a [0.50,1.41,3.00,3.37,3…...
单调队列【C/C++】
当我在网上搜索了一大堆单调队列的文章后, 我人傻了!? 单调队列不应该很难吗?? 不应该是,像 优先队列 那样,站在 堆 的肩膀上,极尽升华吗??? …...
Spark DataFrame、Dataset 和 SQL 解析原理深入解析(万字长文多张原理图)
目录 1. Spark SQL 概述 1.1 Spark 整体架构概览 1.2 DataFrame 与 Dataset 简介 2. RDD 与 Spark 的分布式架构基础 2.1 弹性分布式数据集(RDD) 2.2 Spark 的分布式执行模型 3. SQL 解析流程与 Catalyst 优化器 3.1 SQL 解析流程概述 3.2 解析阶段与抽象语法树(AST…...
算法系列——有监督学习——3.逻辑回归
一、概述 逻辑回归是一种学习某个事件发生概率的算法。利用这个概率,可以对某个事件发生或不发生进行二元分类。虽然逻辑回归本来是二元分类的算法,但也可以用于三种类别以上的分类问题。为了理解这个算法,请思考以下例子。 你在回家的路上发…...
深入理解traceroute命令及其原理
traceroute 是一个网络诊断工具(Windows上叫tracert),用于显示数据包从本地主机到远程主机经过的路由(跳数)。它可以帮助您了解数据包在网络中的传输路径,以及每跳的延迟情况。这对于网络故障排除、分析网络…...
