news 2026/5/1 7:48:19

Qt之多线程和并发_P2

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt之多线程和并发_P2

在使用多线程时需要时刻注意一点的时,多个线程在访问同一个资源时会抢夺资源,造成数据不一致,严重影响程序结果甚至崩溃。为了防止竞态条件的发生,使用多线程时需要实现线程同步,也即确保多个线程在同时使用共享资源时不会发生冲突或数据不一致。
Qt提供了互斥锁、信号量、条件变量、读写锁以及原子操作等机制实现线程同步。

文章目录

    • 互斥锁
    • 读写锁
    • 条件变量
    • 信号量

互斥锁

互斥锁QMutex是最常用的一种同步机制,用于保护一个对象或数据结构或一段代码,确保同一时间只有一个线程访问它们。

方法说明
lock()对互斥资源加锁,如果有其他线程拥有当前锁,调用此函数会阻塞直到其他线程释放了锁,通常与unlock()成套使用。注意不要对同一个互斥量多次加锁,否则会造成死锁
tryLock(int timeout)尝试获取互斥锁,如果获取成功返回true,否则返回false,如果另一个线程已经锁定了该互斥量,此函数将等待直到达到设定的超时时间(ms),如果成功获得了锁,则必须在其他线程能够成功锁定该互斥量之前,调用unlock()将其解锁。从同一线程中对同一个互斥量多次调用此函数将导致死锁。
try_lock()等同于不带参数的tryLock(),是为了与标准库兼容而提供的
unlock()释放当前持有的锁,需与lock()成对使用。试在与锁定该互斥量不同的线程中对其进行解锁会导致错误。对一个未被锁定的互斥量执行解锁操作将导致未定义行为

QMutex在使用时需要手动锁定和解锁。在简单的程序中尚可,在复杂程序中很容易忽略细节而出现问题,我们推荐QMutexLocker配合QMutex一起使用。QMutexLocker是利用RAII机制,在构造函数中加锁,析构函数中解锁,因此不需要我们手动加锁和解锁,使用更方便。为此QMutexLocker对象通常创建为局部变量,并传入一个未加锁的QMutex指针变量(若是锁定,可用relock()重新锁定或unlock())。

QMutex lock; void TestThread::run() { ... lock.lock(); dosomething(); lock.unlock(); ... } void TestThread::run() { ... QMutexLocker(&lock); dosomething(); ... }

有些场景如函数递归或重入,注意要避免重复加锁而造成死锁:

QMutex mutex; void increment() { QMutexLocker locker(&mutex); ++count; } void incrementTwice() { QMutexLocker locker(&mutex); // 第一次获取锁 increment(); // ❌ 尝试再次获取同一个锁 → 死锁! }

对于这种情况需要用到递归锁:

QRecursiveMutex mutex; void increment() { QMutexLocker locker(&mutex); ++count; } void incrementTwice() { QMutexLocker locker(&mutex); //第一次获取锁 increment(); // 第二次获取同一个锁,递归 } //析构时释放2次锁

递归锁需要记录持有者和次数,性能略低于普通锁,而且可能隐藏设计问题,因优先优化代码架构。

读写锁

QReadWriteLock读写锁允许多个线程同时以只读方式访问资源,但一旦有某个线程需要写入资源,所有其他线程(无论是读还是写)都必须被阻塞,直到写操作完成。在许多情况下,QReadWriteLockQMutex的直接替代方案。如果应用程序中存在大量并发读取操作,而写入操作相对较少,则使用QReadWriteLock是一个很好的选择。
QReadWriteLock正常情况下多个读者可以同时读(并发),一旦有写者在排队等候(即使没有开始写),系统也会阻止新读者加入,已经在读的读者可以继续读完,但新来的读者必须等待写者完成,这样设计的目的是防止读者源源不断的到来,写者永远等不到读者的时刻,写者被饿死。当有一个写者W1持有写锁,此时读者R1、R2在排队等候,如果有新的写者W2到来,即使R1、R2等得更久,W2也会优先于R1、R2获得锁,也即写者优先。

特性QMutexQReadWriteLock
锁类型互斥锁读写锁
并发读不支持允许多个线程同时读
写操作与其他任何操作互斥写时禁止所有其他读写
使用场景读写频率相近,或写多读少读多写少

QReadWriteLock类常用的方法包括lockForRead()lockForWrite()以及unlock()lockForRead()lockForWrite()需要和unlock()配套使用。

QReadWriteLock lock; void ReaderThread::run() { ... lock.lockForRead(); read_file(); lock.unlock(); ... } void WriterThread::run() { ... lock.lockForWrite(); write_file(); lock.unlock(); ... }

为了防止unlock()忘记调用,推荐使用QWriteLockerQReadLocker,这是利用了RAII机制,在构造的时候加锁,析构的自动解锁。
上述代码等效于:

void ReaderThread::run() { ... QReadLocker locker(&lock); read_file(); ... } void WriterThread::run() { ... QWriteLocker locker(&lock); write_file(); ... }

条件变量

QWaitCondition是Qt条件变量的实现,它通常配合互斥锁(QMutex)或读写锁(QReadWriteLock)使用,用来让线程在某个条件为真之前阻塞等待,由其他线程在条件改变后调用 wakeOne()/wakeAll() 唤醒。
条件变量和QMutex不同,QMutex要解决的问题是互斥,要保证同一时间只有一个线程进入,防止数据竞争,而QWaitCondition是要解决的是条件等待以及唤醒线程的问题,它能够高效的利用资源,避免无意义的轮询,充分利用CPU资源。

以生产者线程和消费者模型为例,如果只用QMutex同步线程,消费者线程需要不断地轮询检查:获取锁–>检查队列–>还为空–>睡眠–>再次获取锁…
这样如果队列为空CPU就会陷入忙等,白白浪费CPU资源,如果队列不为空,其他线程可能需要等到下一个轮询点才发现队列不为空,反应迟钝。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 2:52:09

阿里2026版Spring全家桶高级笔记

不知道各位Java好大哥们闲的时候会不会去关注Spring目前的官网,你会发现他的slogan是: Spring makes Java Simple。它让Java的开发变得更加简单。某种意义上来说:是Spring成就了Java!但随之而来的就是:由他之后诞生出来的各种组件…

作者头像 李华
网站建设 2026/5/1 7:27:02

悬鉴与“养护人叙事环”的建构:算法治理的微观政治学

悬鉴与“养护人叙事环”的建构:算法治理的微观政治学笔者:岐金兰摘要当代算法治理陷入了“批判愈多,治理愈空”的实践困境。其根源在于主流范式困于“主体-客体”框架,将“算法”视为待规制的静态客体,而系统性忽视了算…

作者头像 李华
网站建设 2026/5/1 7:30:57

基于深度学习的图像风格迁移系统[python]-计算机毕业设计源码+LW文档

摘要:图像风格迁移作为计算机视觉和图形学中的热门研究方向,旨在将一幅图像的艺术风格应用到另一幅图像的内容上,创造出具有特定风格的新图像。本文深入探讨了基于深度学习的图像风格迁移技术,阐述了其基本原理、常见方法&#xf…

作者头像 李华
网站建设 2026/4/18 20:22:56

搞IGBT仿真最刺激的就是看不同工况下参数如何跳舞。今天这两个模型玩出了新花样,特别是事件接口的应用,直接把仿真工程师的头发又薅下来几根

IGBT模型。 本次发送的模型共有2个,部分有视频介绍及参考文献。 1.图1-4研究了多周期通电下IGBT的各参数变化,0-2s通电2V,2-4s断电即为0V,以此类推,采用的物理场为固体传热、电流、固体力学、事件、疲劳等物理场和电磁…

作者头像 李华
网站建设 2026/4/17 4:06:29

DOTA2 无法找到 msvcp140.dll 怎么解决?AI助你一键修复

核心问题:启动DOTA2时弹出“无法找到msvcp140.dll”提示,导致游戏无法正常启动、闪退或无法进入加载界面。 结论:虽然可以通过手动排查修复问题,但由于步骤繁琐、需具备一定电脑专业知识,且容易出现操作失误导致问题加…

作者头像 李华
网站建设 2026/4/20 1:32:08

【开题答辩全过程】以 基于Web的旅游攻略平台的设计与开发为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人,语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

作者头像 李华