【Qt】多线程

news/2024/5/19 11:25:32/文章来源:https://blog.csdn.net/GG_Bruse/article/details/137438821

目录

一、常用API

二、线程安全

2.1 互斥锁

2.2 条件变量

2.3 信号量 


在Qt中,多线程的处理一般是通过QThread类来实现

QThread代表一个在应用程序中可以独立控制的线程,也可以和进程中的其他线程共享数据。QThread对象管理程序中的一个控制线程

一、常用API

run()线程入口函数
start()

通过调用run()函数开始执行线程,操作系统根据优先级参数调度线程

若线程已在运行,该函数说明也不做

currentThread()返回一个指向 管理当前执行线程 的QThread的指针
isRunning()若线程正在运行返回true,否则返回false
sleep()/msleep()/usleep()实现线程休眠,单位为秒/毫秒/微秒
wait()

阻塞线程,直到满足以下任何一个条件:

与此QThread对象关联的线程已经完成执行(即当它从run()返回时),若线程已经完成,这个函数将返回true;若线程尚未启动,也返回true

已经过了几毫秒,若时间是ULONG_MAX(默认值),那么等待永远也不会超时(线程必须从run()返回)。若等待超时,此函数返回false

与POSIX pthread_join() 函数类似

terminate()终止线程的执行。线程可以立即终止,也可以不立即终止,取决于操作系统的调度策略。在terminate()之后使用QThread::wait()来确保终止
finished()当线程结束时会发出该信号,可以通过该信号来实现线程的清理工作

创建线程的步骤:

  1. 自定义一个类,继承于QThread,并且只有一个线程处理函数(和主线程不是同一个线程),这个线程处理函数主要就是重写父类中的 run()函数
  2. 线程处理函数里面写入需要执行的复杂数据处理
  3. 启动线程不能直接调用 run() 函数,需要使用对象来调用 start() 函数实现线程启动
  4. 线程处理函数执行结束后可以定义一个信号来告诉主线程
  5. 最后关闭线程

代码示例

新建 Qt 项目,设计UI界面如下:

新建一个类,继承于QThread类

thread.h

#ifndef THREAD_H
#define THREAD_H#include <QWidget>
#include <QThread>
#include <QTime>
#include <QDebug>class Thread : public QThread
{Q_OBJECT
public:Thread();
public:void run();//重写
signals:void sendTime(QString time);//声明信号函数
};#endif // THREAD_H

thread.cpp

#include "thread.h"Thread::Thread() {}void Thread::run()
{while(true){QString time = QTime::currentTime().toString("hh:mm:ss");qDebug() << time;emit sendTime(time);//发送信号sleep(1);}
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "thread.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void startShow();void showTime(QString time);private:Ui::Widget *ui;Thread thread;//声明线程对象
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);connect(ui->pushButton, &QPushButton::clicked, this, &Widget::startShow);connect(&thread, &Thread::sendTime, this, &Widget::showTime);
}Widget::~Widget()
{delete ui;
}void Widget::startShow()
{thread.start();
}void Widget::showTime(QString time)
{ui->label->setText(time);
}

注意:

  • 线程函数内部不允许操作 UI 图形界面,一般用数据处理
  • connect() 函数第五个参数表的为连接的方式,只有在多线程时才有意义

二、线程安全

实现线程互斥和同步常用的类有:

  • 互斥锁:QMutex、QMutexLocker
  • 条件变量:QWaitCondition
  • 信号量:QSemaphore
  • 读写锁:QReadLocker、QWriteLocker、QReadWriteLock 

2.1 互斥锁

互斥锁是一种保护和防止多个线程同时访问同一对象实例的方法,在Qt中,互斥锁主要是通过QMutex类来处理

QMutex

  • 特点:QMutex是 Qt 框架提供的互斥锁类,用于保护共享资源的访问,实现线程间的互斥操作
  • 用途:在多线程环境下,通过互斥锁来控制对共享数据的访问,确保线程安全
QMutex mutex;
mutex.lock(); //上锁
//访问共享资源
//...
mutex.unlock(); //解锁

QMutexLocker

  • 特点:QMutexLocker是QMutex的辅助类,使用RAII(Resource Acquisition Is Initialization)方式对互斥锁进行上锁和解锁操作
  • 用途:简化对互斥锁的上锁和解锁操作,避免忘记解锁、异常等问题导致的死锁
QMutex mutex;
{QMutexLocker locker(&mutex); //在作⽤域内⾃动上锁//访问共享资源//...
} //在作⽤域结束时⾃动解锁

QReadWriteLocker、QReadLocker、QWriteLocker

特点:

  • QReadWriteLock 是读写锁类,用于控制读和写的并发访问
  • QReadLocker 用于读操作上锁,允许多个线程同时读取共享资源
  • QWriteLocker 用于写操作上锁,只允许一个线程写入共享资源

用途:在某些情况下,多个线程可以同时读取共享数据,但只有一个线程能够进行写操作。读写锁提供了更高效的并发访问方式

QReadWriteLock rwLock; //在读操作中使⽤读锁
{QReadLocker locker(&rwLock); //在作⽤域内⾃动上读锁//读取共享资源//...
} //在作⽤域结束时⾃动解读锁//在写操作中使⽤写锁
{QWriteLocker locker(&rwLock); //在作⽤域内⾃动上写锁//修改共享资源//...
} //在作⽤域结束时⾃动解写锁

代码示例

thread.h

#ifndef THREAD_H
#define THREAD_H#include <QWidget>
#include <QThread>
#include <QMutex>
#include <QDebug>class Thread : public QThread
{Q_OBJECT
public:Thread(QObject* parent = nullptr);void run();
private:static QMutex mutex; //多个线程使用一把锁static int number;	 //多个线程访问同一个数据
};#endif // THREAD_H

thread.cpp

#include "thread.h"QMutex Thread::mutex;
int Thread::number;Thread::Thread(QObject* parent):QThread(parent) {}void Thread::run()
{while(true){mutex.lock();qDebug() << "current thread:" << this << ", value:" << number++;mutex.unlock();QThread::sleep(2);//休眠两秒}
}

widget.h 

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "thread.h"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"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);Thread* thread1 = new Thread(this);Thread* thread2 = new Thread(this);thread1->start();thread2->start();
}Widget::~Widget()
{delete ui;
}

2.2 条件变量

  • 特点:QWaitCondition是 Qt 框架提供的条件变量类,用于线程之间的消息通信和同步
  • 用途:在某个条件满足时等待或唤醒线程,用于线程的同步和协调
QMutex mutex;
QWaitCondition condition;//在等待线程中
mutex.lock();
//检查条件是否满⾜,若不满⾜则等待
while (!conditionFullfilled()) {condition.wait(&mutex); //等待条件满⾜并释放锁
} 
//条件满⾜后继续执⾏
//...
mutex.unlock();//在改变条件的线程中
mutex.lock();
//改变条件
changeCondition();
condition.wakeAll(); //唤醒等待的线程
mutex.unlock();

2.3 信号量 

有时在多线程编程中,需要确保多个线程可以相应的访问一个数量有限的相同资源。例如,运行程序的设备内存有限,因此更希望需要大量内存的线程将这一事实考虑在内,并根据可用的内存数量进行相关操作,多线程编程中类似问题通常用信号量来处理。信号量类似于增强的互斥锁,不仅能完成上锁和解锁操作,还可以跟踪可用资源的数量

  • 特点:QSemaphore是 Qt 框架提供的计数信号量类,用于控制同时访问共享资源的线程数量
  • 用途:限制并发线程数量,用于解决一些资源有限的问题
QSemaphore semaphore(2); //同时允许两个线程访问共享资源//在需要访问共享资源的线程中
semaphore.acquire(); //尝试获取信号量,若已满则阻塞
//访问共享资源
//...
semaphore.release(); //释放信号量
//在另⼀个线程中进⾏类似操作

 

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入探索力扣第12题:整数转罗马数字的算法之旅

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 欢迎加入社区&#xff1a;码上找工作http://t.csdnimg.cn/Q59WX作者专栏每日更新&#xff1a; LeetCode解锁1000题: 打…

业务逻辑漏洞(靶场) fiddler

目录 fiddler简介&#xff1a; 业务逻辑漏洞&#xff1a; fiddler下载 靶场&#xff1a; 实验一 ​编辑实验二&#xff08;ps 更改实验url会变&#xff0c;fiddler没抓到东西看看代理改没改&#xff09; 实验三 实验四 fiddler简介&#xff1a; 一款网络抓包工具&#…

ht1622不显示无反应问题解决

如果你正在写ht1622 驱动时&#xff0c;怎么看程序都没问题&#xff0c;抓取波形&#xff0c;示波器分析波形&#xff0c;如果都没有问题&#xff0c;那么很大可能是硬件问题&#xff0c;检测看看 ht1622 RD是不是接地了。 RD 低会进入读取模式&#xff0c;所以不用RD 请将RD悬…

雄安建博会:中矿雄安新区的总部开工建设

中矿落位雄安&#xff1a;助力国家战略与新区发展 雄安新区&#xff0c;作为中国未来发展的重要战略支点&#xff0c;正迎来一系列央企总部的疏解与建设。最近&#xff0c;中国矿产资源集团有限公司&#xff08;简称“中矿”&#xff09;在雄安新区的总部项目正式开工建设&…

Jettison 1.8.7直装版 外部磁盘辅助弹出

Jettison 是一款适用于 macOS 的实用工具&#xff0c;旨在简化外部驱动器的管理。它可以自动卸载和重新挂载外部驱动器&#xff0c;帮助您更方便地使用和保护您的存储设备。 软件下载&#xff1a;Jettison 1.8.7直装版下载 自动卸载和重新挂载&#xff1a;Jettison 可以在您离开…

yolo预标注的txt转换成labelme中segment的json

前言 在yolo预标注的时候&#xff0c;想把保存的txt转换成labelme中segment的json&#xff0c;于是写了下面的脚本。 1.引入库 完整代码&#xff1a; import os import json from tqdm import tqdmdef get_image_size(image_path):from PIL import Imagewith Image.open(ima…

Spring boot如何执行单元测试?

Spring Boot 提供了丰富的测试功能&#xff0c;主要由以下两个模块组成&#xff1a; spring-boot-test&#xff1a;提供测试核心功能。spring-boot-test-autoconfigure&#xff1a;提供对测试的自动配置。 Spring Boot 提供了一个 spring-boot-starter-test一站式启动器&…

unipush+个推实现消息推送

1.注册个推平台的帐号个推&#xff0c;专业的数据智能服务商-为垂直领域提供数据智能解决方案 2.应用列表中选择新增应用/服务 3.填写下应用信息4.创建好应用后在manifest.json中的sdkConfigs配置上写入appid、appkey、appsecret "sdkConfigs" : {"ad" :…

硬件学习件Cadence day16 做个笔记,BOM 位号这个参数输出的两种情况。

1. BOM 中位号有3种情况 1. 一种是位号生成时多行&#xff0c;每行是固定的位数。&#xff08;如下图所示&#xff09; 2. 一种是位号生成时只有一行&#xff0c;但是可以使用表格中自动换行功能&#xff0c;给他换行&#xff0c;但是这个位号本质上只有一行&#xff0c;只是因…

基于深度学习的乳腺癌智能检测分割与诊断系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战、目标分割、人工智能

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

虚拟网络设备的真正使命:实现有控制的通信

在数字化时代&#x1f4f2;&#xff0c;网络安全&#x1f512;成为了企业和个人防御体系中不可或缺的一部分。随着网络攻击的日益复杂和频繁&#x1f525;&#xff0c;传统的物理网络安全措施已经无法满足快速发展的需求。虚拟网络设备&#x1f5a7;&#xff0c;作为网络架构中…

一起学习python——基础篇(5)

今天讲一下python的数据类型。 数据类型主要分为文本类型、数值类型、序列类型、映射类型、集合类型、布尔类型、二进制类型六大类型。 文本类型&#xff1a;str 数值类型&#xff1a; int, float, complex 序列类型&#xff1a; list, tuple, range 映射类型&#xff1a;…

【数据结构与算法】搜索算法(深度优先搜索 DFS和广度优先搜索 BFS)以及典型算法例题

目录 搜索算法&#xff08;深度优先搜索DFS和广度优先搜索BFS&#xff09;以及典型算法例题深度优先搜索 &#xff08;Depth First Search 简称 DFS&#xff09;DFS 的设计步骤深度优先搜索&#xff08;DFS&#xff09;算法例题例题一&#xff1a;N皇后问题例题二&#xff1a;路…

SQL注入sqli_labs靶场第五、六题

第五题 根据报错信息&#xff0c;判断为单引号注入 没有发现回显点 方法&#xff1a;布尔盲注&#xff08;太耗时&#xff0c;不推荐使用&#xff09; 1&#xff09;猜解数据库名字&#xff1a;&#xff08;所有ASCII码值范围&#xff1a;0~127&#xff09; ?id1 and length…

成功解决> 错误: 无效的源发行版:17

运行项目的时候出现下面的报错&#xff1a; Execution failed for task ‘:device_info_plus:compileDebugJavaWithJavac’. 错误: 无效的源发行版&#xff1a;17 原因&#xff1a;没有设置好自己项目的JDK版本 解决&#xff1a;1.检查自己项目的JDK版本 将自己的项目改为JDK 1…

MySQL高级(索引分类-聚集索引-二级索引)

目录 1、主键索引、唯一索引、常规索引、全文索引 2、 聚集索引、二级索引 3、回表查询 4、通过id查询和通过name查询那个执行效率高&#xff1f; 5、 InnoDB主键索引的 B tree 高度为多高呢&#xff1f; 1、主键索引、唯一索引、常规索引、全文索引 在MySQL数据库&#xff0c…

C++的stack和queue类(一):适配器模式、双端队列与优先级队列

目录 基本概念 stack的使用 queue的使用 适配器模式 stack.h test.cpp 双端队列-deque 仿函数 优先队列 priority_queue的使用 queue.h文件 stack.h文件 test.cpp文件 日期类的比较 商品的比较 结论 基本概念 1、stack和queue不是容器而是容器适配器&…

性能优化原则

相关链接&#xff1a;【运行环境】加载资源的形式 性能优化 1 性能优化原则 多使用内存、缓存或其他方法 减少CPU计算量&#xff0c;减少网络加载耗时 &#xff08;适用于所有编程的性能优化----空间换时间&#xff09; 2 从何入手 性能优化-让加载更快 减少资源体积&#x…

每日一题 — 最大连续 1 的个数III

解法一&#xff1a;暴力枚举 先定义left和right双指针&#xff0c;left先固定在起始位置&#xff0c;遍历right当值等于1的时候&#xff0c;直接跳过&#xff0c;等于0的时候&#xff0c;zero计数器加一当zero等于k的时候&#xff0c;就开始记录此时最大长度是多少然后left加一…

深度剖析:网络安全中的红蓝对抗策略

红蓝对抗 红蓝对抗服务方案 在蓝队服务中&#xff0c;作为攻击方将开展对目标资产的模拟入侵&#xff0c;寻找攻击路径&#xff0c;发现安全漏洞和隐患。除获取目标系统的关键信息&#xff08;包括但不限于资产信息、重要业务数据、代码或管理员账号等&#xff09;外&#x…