Qt/C++ 多线程同步机制详解及应用

在多线程编程中,线程之间共享资源可能会导致数据竞争和不一致的问题。因此,采用同步机制确保线程安全至关重要。在Qt/C++中,常见的同步机制有:互斥锁(QMutexstd::mutex)、信号量(QSemaphore)、读写锁(QReadWriteLock)、原子操作(QAtomicInt 等)以及条件变量(QWaitConditionstd::condition_variable)。本文将详细介绍这些常用同步机制,并通过代码示例帮助理解其使用场景。

在这里插入图片描述

1. 互斥锁(QMutex / std::mutex

互斥锁是最常用的线程同步机制之一,它可以保证在同一时刻只有一个线程进入临界区。其基本原理是通过锁定和解锁互斥锁来确保共享资源的独占访问。

示例代码及注释
#include <QMutex>
#include <QThread>
#include <iostream>// 声明一个全局互斥锁,用于保护共享资源
QMutex mutex;
int sharedResource = 0;  // 共享资源class Worker : public QThread {
public:void run() override {mutex.lock();  // 锁定互斥锁,确保当前线程独占资源std::cout << "Thread " << QThread::currentThreadId() << " is entering the critical section." << std::endl;sharedResource++;  // 修改共享资源std::cout << "Shared Resource: " << sharedResource << std::endl;mutex.unlock();  // 释放互斥锁,其他线程可以进入}
};int main() {Worker worker1, worker2;  // 创建两个工作线程worker1.start();  // 启动第一个线程worker2.start();  // 启动第二个线程worker1.wait();   // 等待第一个线程完成worker2.wait();   // 等待第二个线程完成return 0;
}
解释:
  1. 互斥锁机制:使用 mutex.lock() 锁定,mutex.unlock() 解锁,保证共享资源在某个线程执行完后才可被其他线程访问。
  2. 线程独占性:多个线程同时访问共享资源时,只有获取到锁的线程能进入临界区,避免竞争条件。

2. 信号量(QSemaphore

信号量是一种同步机制,用于控制多个线程同时访问有限数量的资源。与互斥锁不同,信号量可以允许多个线程并发访问,直到信号量资源用尽。

示例代码及注释
#include <QSemaphore>
#include <QThread>
#include <iostream>// 初始化信号量,允许最多3个线程同时进入临界区
QSemaphore semaphore(3);class Worker : public QThread {
public:void run() override {semaphore.acquire();  // 获取信号量std::cout << "Thread " << QThread::currentThreadId() << " is entering." << std::endl;QThread::sleep(1);    // 模拟执行任务的时间std::cout << "Thread " << QThread::currentThreadId() << " is leaving." << std::endl;semaphore.release();  // 释放信号量}
};int main() {Worker worker1, worker2, worker3, worker4;  // 创建四个线程worker1.start();  // 启动线程worker2.start();worker3.start();worker4.start();  // 第四个线程需等待其他线程释放信号量worker1.wait();worker2.wait();worker3.wait();worker4.wait();return 0;
}
解释:
  1. 并发控制:信号量通过 acquire() 获取资源,release() 释放资源,控制多个线程并发执行。
  2. 资源计数:当信号量值为零时,其他线程必须等待信号量被释放才能继续执行。

3. 读写锁(QReadWriteLock

读写锁允许多个线程同时读取共享资源,但只有一个线程可以进行写入操作。它适合在多读少写的场景中使用,能有效提高读取操作的并发性能。

示例代码及注释
#include <QReadWriteLock>
#include <QThread>
#include <iostream>// 读写锁,保护共享资源
QReadWriteLock lock;
int sharedResource = 0;  // 共享资源class Reader : public QThread {
public:void run() override {lock.lockForRead();  // 获取读锁std::cout << "Reader thread " << QThread::currentThreadId() << " reading: " << sharedResource << std::endl;lock.unlock();  // 释放读锁}
};class Writer : public QThread {
public:void run() override {lock.lockForWrite();  // 获取写锁sharedResource++;std::cout << "Writer thread " << QThread::currentThreadId() << " writing: " << sharedResource << std::endl;lock.unlock();  // 释放写锁}
};int main() {Reader reader1, reader2;  // 创建两个读线程Writer writer1;  // 创建一个写线程reader1.start();reader2.start();writer1.start();  // 写线程将阻塞后续的读操作reader1.wait();reader2.wait();writer1.wait();return 0;
}
解释:
  1. 多读单写lock.lockForRead() 允许多个线程同时读取,而 lock.lockForWrite() 则保证写操作期间的独占访问。
  2. 适用场景:在多读少写的场景下,读写锁可以提高效率。

4. 原子操作(QAtomicInt / std::atomic

原子操作是一种无需锁定的同步方式,适合处理简单的共享数据操作,如计数器的增减。它通过硬件保证操作的原子性,从而避免了线程间的数据竞争。

示例代码及注释
#include <QAtomicInt>
#include <QThread>
#include <iostream>// 原子整型,用于原子递增
QAtomicInt atomicCounter = 0;class Worker : public QThread {
public:void run() override {for (int i = 0; i < 1000; ++i) {atomicCounter.ref();  // 原子递增操作}}
};int main() {Worker worker1, worker2;  // 创建两个线程worker1.start();worker2.start();worker1.wait();worker2.wait();std::cout << "Final counter: " << atomicCounter.load() << std::endl;  // 输出最终的计数值return 0;
}
解释:
  1. 轻量同步atomicCounter.ref() 是一个原子操作,不需要使用互斥锁,适合简单的递增或递减操作。
  2. 性能提升:相比于使用锁,原子操作的性能开销更小,非常适合对共享资源进行计数的场景。

5. 条件变量(QWaitCondition / std::condition_variable

条件变量用于线程间的同步,它允许线程等待某个条件被满足,通常与互斥锁一起使用。在条件满足时,可以唤醒一个或多个等待的线程。

示例代码及注释
#include <QMutex>
#include <QWaitCondition>
#include <QThread>
#include <iostream>// 声明互斥锁和条件变量
QMutex mutex;
QWaitCondition condition;
bool ready = false;  // 条件标志class Worker : public QThread {
public:void run() override {mutex.lock();  // 获取互斥锁while (!ready) {condition.wait(&mutex);  // 等待条件满足,期间释放互斥锁}std::cout << "Thread " << QThread::currentThreadId() << " is processing." << std::endl;mutex.unlock();  // 释放互斥锁}
};int main() {Worker worker1, worker2;  // 创建两个线程worker1.start();worker2.start();QThread::sleep(1);  // 模拟主线程准备时间mutex.lock();ready = true;condition.wakeAll();  // 唤醒所有等待的线程mutex.unlock();worker1.wait();worker2.wait();return 0;
}
解释:
  1. 条件等待:线程使用 condition.wait() 进入等待状态,直到条件满足时被唤醒。
  2. 唤醒机制condition.wakeAll() 唤醒所有正在等待条件的线程,使它们重新进入竞争状态。

在多线程编程中,选择合适的同步机制是确保数据安全和程序高效运行的关键。根据不同的应用场景,互斥锁、信号量、读写锁、原子操作和条件变量各有优缺点:

  • 互斥锁 适用于保护临界区,确保共享资源的独占访问;
  • 信号量 控制并发资源的访问数量;
  • 读写锁 适合多读少写的场景,提升读取性能;
  • 原子操作 在简单的共享数据操作中高效且轻量;
  • 条件变量 允许线程等待某个条件的满足,以实现灵活的线程同步。

合理使用这些工具能够有效避免多线程编程中的竞争条件,确保程序的安全和性能。

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

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

相关文章

多模态大模型MiniCPM-V技术学习

目前性价比最高的多模态模型 Minicpm-V-2.6参数8B&#xff0c;int4版本推理显存仅7GB&#xff0c;并且在幻觉数据集上效果好于其他模型&#xff0c;测试下来效果非常好&#xff0c;官方演示里面还给出了手机上端侧运行的图片和视频推理示例 p.s.Qwen2-VL和Minicpm-V-2.6头对头…

【操作系统】02.深入理解操作系统

一、操作系统的定位 任何计算机系统都包含一个基本的程序集合&#xff0c;称为操作系统(OS)。笼统的理解&#xff0c;操作系统包括操作系统内核和其他程序。 由上述的宏观图其实我们就知道&#xff1a;操作系统是一款进行软硬件资源管理的软件。 二、设计操作系统的目的 操…

众数信科AI智能体政务服务解决方案——寻知智能笔录系统

政务服务解决方案 寻知智能笔录方案 融合民警口供录入与笔录生成需求 2分钟内生成笔录并提醒错漏 助办案人员二次询问 提升笔录质量和效率 寻知智能笔录系统 众数信科AI智能体 产品亮点 分析、理解行业知识和校验规则 AI实时提醒用户文书需注意部分 全文校验格式、内…

C一语言—动态内存管理

目录 一、为什么要有动态内存管理 二、malloc和free &#xff08;2.1&#xff09;malloc &#xff08;2.2&#xff09;free 三、calloc和realloc &#xff08;3.1&#xff09;calloc &#xff08;3.2&#xff09;realloc 四、常见的动态内存的错误&#xff08;举例均为错…

springboot每次都需要重设密码?明明在springboot的配置中设置了密码

第一步&#xff1a;查看当前的密码是什么&#xff1f; 打开redis-cli.exe&#xff0c;输入config get requirepass&#xff0c;查看当前的密码是什么&#xff1f; 接着&#xff0c;修改redis的配置文件&#xff0c;找到redis的安装目录&#xff0c;找到相关的conf文件&#x…

Amazon Bedrock 模型微调实践(二):数据准备篇

本博客内容翻译自作者于 2024 年 9 月在亚马逊云科技开发者社区发表的同名博客&#xff1a; “Mastering Amazon Bedrock Custom Models Fine-tuning (Part 2): Data Preparation for Fine-tuning” 亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、…

Unity3D入门(一) : 第一个Unity3D项目,实现矩形自动旋转,并导出到Android运行

1. Unity3D介绍 Unity3D是虚拟现实行业中&#xff0c;使用率较高的一款软件。 它有着强大的功能&#xff0c;是让玩家轻松创建三维视频游戏、建筑可视化、实时三维动画等互动内容的多平台、综合型 虚拟现实开发工具。是一个全面整合的专业引擎。 2. Unity安装 官网 : Unity…

1042 Shuffling Machine,1050 String Subtractio

1042 Shuffling Machine 普通模拟即可&#xff0c;注意每一次交换牌的时候需要更新start数组&#xff08;当前卡牌的顺序&#xff09;&#xff0c;并且清空ans数组&#xff08;交换后的卡牌顺序&#xff09; #include<bits/stdc.h> using namespace std; const int N 5…

hal 正点原子 exti外部中断

1.这个是 f4/f7/h7 用于配置外部中断的寄存器 需要先使能时钟 2.这个是f1用于配置外部中断的配置器&#xff0c;也是需要先配置时钟&#xff0c;但是区别在于除了f1 &#xff0c;别的系列都用的SYSCFG 3.这个是外部中断线io和怎么exti对应的 4.这两张图 都是exti和io的对应关系…

QFramework v1.0 使用指南 更新篇:20240919. 新增 BindableDictionary

虽然笔者目前还不知道 BindableDictionary 能用在什么使用场景下&#xff0c;但是还是应童鞋的要求实现了 BindableDictionary。 基本使用如下: using System.Linq; using UnityEngine;namespace QFramework.Example {public class BindableDictionaryExample : MonoBehaviou…

【设计模式】UML类图

目录 前言 一、类图概述 二、类图的作用 三、类图表示法 四、类之间关系的表示方法 1. 关联关系 1.1 单向关联 1.2 双向关联 1.3 自关联 2. 聚合关系 3. 组合关系 4. 依赖关系 5. 继承关系 6. 实现关系 总结 前言 统一建模语言&#xff08; Unified Modeling La…

ClickHouse 的第一篇 研究论文:如何让现代数据分析数据库实现超高速性能?

本文字数&#xff1a;3245&#xff1b;估计阅读时间&#xff1a;9 分钟 作者&#xff1a;ClickHouse Team 本文在公众号【ClickHouseInc】首发 我们非常激动地宣布&#xff0c;第一篇关于 ClickHouse 的研究论文【chrome-extension://mhnlakgilnojmhinhkckjpncpbhabphi/pages/p…

基于ACMEv2协议的免费SSL证书申请-支持Let‘s Encrypt/Google/ZeroSSL

项目&#xff1a;https://github.com/cook-code-jazor/acmex 非开源&#xff0c;使用webui管理证书的申请&#xff0c;所有文件本地化存储&#xff0c;支持windows/linux/osx。 证书申请直连ACMEv2服务商&#xff0c;没有任何中间接口&#xff0c;支持Lets Encrypt/Google/Ze…

Inf-MLLM:单个 4090D 实现 4M Token 长序列问答

一、背景 本文中我们简单介绍一个新的解决长序列推理效率的新方案 Inf-MLLM&#xff0c;也是基于 Token 稀疏化。有关 Token 稀疏化的方案通常可以从如下几个方面了解&#xff1a; 怎么识别关键 Token&#xff0c;包括静态识别或动态识别&#xff0c;比如 Streaming LLM 里 At…

从观《中国数据库前世今生》纪录片谈起:云数据库的未来发展与挑战

从观《中国数据库前世今生》纪录片谈起&#xff1a;云数据库的未来发展与挑战 前言 作为一名资深程序员&#xff0c;我在职业生涯中始终密切关注数据库技术的发展动态。近日&#xff0c;我观看了《中国数据库前世今生》这部纪录片&#xff0c;深受触动。这部纪录片不仅记录了…

Ubuntu 安装和使用 Fcitx 中文输入法;截图软件flameshot

一、Ubuntu 安装和使用 Fcitx 中文输入法 在 Ubuntu 上安装和使用 Fcitx 输入法框架是一个常见的选择&#xff0c;特别是对于需要中文输入的用户。以下是详细的步骤来安装和配置 Fcitx 输入法&#xff1a; 1. 安装 Fcitx 和相关输入法 首先&#xff0c;更新你的包列表并安装…

经济下行,这个AI美女短视频带货副业赛道,为什么不来试一试?

经济下行&#xff0c;普通人应该尽早认清一个事实&#xff0c;没有一技之长&#xff0c;没有核心竞争力&#xff0c;即便是打工皇帝&#xff0c;年入百万也只是浮云。 一定要保证主业的稳定&#xff0c;再探索新的机会&#xff0c;要多从”1-10"&#xff0c;而不是反复”…

昇思量子计算系列教程-Grover搜索算法

基于MindSpore Quantum的Grover搜索算法 概述 如果你听过量子计算&#xff0c;那么你一定听说过Grover搜索算法。1996年&#xff0c;Lov Grover [1] 提出了Grover搜索算法&#xff0c;它是一种利用量子状态的叠加性进行并行计算并实现加速的算法。Grover搜索算法被公认为是继…

《让手机秒变超级电脑!ToDesk云电脑、易腾云、青椒云移动端评测》

前言 科技发展到如今2024年&#xff0c;可以说每一年都在发生翻天覆地的变化。而云上这个词时常都被大家提起&#xff0c;从个人设备连接到云端在如今在也不是梦了。而云电脑这个市场近年来迅速发展&#xff0c;无需购买和维护额外的硬件就可以体验到电脑端顶配的性能和体验&am…

ESP32本地大模型对话机器人制作教程

整体架构 在本地电脑部署好Ollama服务&#xff0c;安装qwen大模型和llama3.1大模型。 ESP32接入局域网&#xff0c;用户通过串口给esp32发送问题&#xff0c;esp32打包json后向ollama服务发送请求&#xff0c;ollama返回响应&#xff0c;esp32解析结果并通过串口打印出来。 …