QT--线程

一、线程QThread

  • QThread 类提供不依赖平台的管理线程的方法,如果要设计多线程程序,一般是从 QThread继承定义一个线程类,在自定义线程类里进行任务处理。
  • qt拥有一个GUI线程,该线程阻塞式监控窗体,来自任何用户的操作都会被gui捕获到,并处理;如果有耗时的任务,不推荐在GUI中处理.怎么办?? 创建线程,交给线程去耗时!

1.QThread类简要说明

  1. 一个QThread类的对象管理一个线程。该线程包括
  • 执行函数体,这是线程执行的主要代码部分。
  • 函数体中有一个死循环,用于保持线程的持续运行,直到条件满足。
  • 线程私有空间,每个线程都有自己的独立数据和堆栈空间。
  1. QThread 提供了完整的线程功能,并且内置了一个虚函数 run() 用于处理线程任务。我们可以通过重写 run() 方法来定义线程的具体行为。编写线程的具体方法为继承QThread并重写run()函数。最好是直接定义一个线程类(实际上也这样做)。
  2. GUI线程和控件访问:只有主GUI线程可以访问和操作窗体上的控件。如果其他线程尝试直接访问这些控件,会导致程序崩溃。为了在线程中更新UI,可以使用信号和槽机制。
class MyThread : public QThread {Q_OBJECT
signals:void updateUI(int value);public:void run() override {for (int i = 0; i < 10; ++i) {emit updateUI(i); // 发出信号更新UIQThread::sleep(1);}}
};// 在主窗口类中连接信号和槽
connect(ptMyThread, &MyThread::updateUI, this, &MainWindow::updateUIFunction);
  1. 线程的启动和停止使用start()和stop()函数即可。这也是可以捕获的信号,可以用来连接槽函数,不过要加上ed。
  2. 出现了此类错误error: undefined reference to `vtable for myThread,那么就将该错误发生的头文件和函数体文件移除该工程,然后再添加进来。
  3. 代码举例
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

2.线程间通信

1.通过共享资源的方式可以进行线程间通信。

  1. 结构体通信
    1. 值得注意的就是使用之前要加锁,使用之后要解锁
QMutex buflock;//其实就是互斥信号量。
buflock.lock();
buflock.unlock();
    1. 结构体要在使用该结构体的线程中声明,定义在外面,方便其他线程使用或声明,当然互斥锁也要有哈。
    1. 一般通过构造函数传入或写出数据。
    1. 在重写run()函数里有while循环,或者是死循环,具体情况而定
    1. 当然也要有休眠函数,给其他线程一点时间执行嘛。
    1. 代码举例
//rethread.h
#ifndef RETHREAD_H
#define RETHREAD_H
#include<QThread>
#include<QMutex>struct msg_struct{int temp;int shidu;char des[128];
};class thread_write:public QThread{
public:thread_write();thread_write(struct msg_struct *pmsg,QMutex *pMutex);//写~thread_write();void run() override;//写。重写
private:struct msg_struct *pShareMsg;QMutex *pMutex;
};class thread_read:public QThread{
public:thread_read(struct msg_struct *pmsg,QMutex *pMutex);//写thread_read();~thread_read();void run() override;//重写
private:struct msg_struct *pShareMsg;QMutex *pMutex;};#endif // RETHREAD_H//rethread.cpp
#include "rethread.h"
#include<QDebug>thread_write::thread_write()
{}thread_write::thread_write(msg_struct *pmsg, QMutex *pMutex)
{pShareMsg = pmsg;this->pMutex=pMutex;
}thread_write::~thread_write()
{}void thread_write::run()
{char ch = 'A';while(1){pMutex->lock();for(int i= 0;i<127;i++){pShareMsg->des[i]=ch;if(i%20==0){QThread::sleep(1);}}pMutex->unlock();QThread::msleep(10);ch++;}
}thread_read::thread_read(msg_struct *pmsg, QMutex *pMutex)
{pShareMsg = pmsg;this->pMutex = pMutex;}thread_read::thread_read()
{}thread_read::~thread_read()
{}void thread_read::run()
{QThread::sleep(1);while(1){pMutex->lock();qDebug()<<"thread read"<<__func__<<" "<<pShareMsg->des;pMutex->unlock();QThread::sleep(5);}
}//widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include"rethread.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;struct msg_struct *pShareMsg;QMutex *pMutex;thread_read *pThreadRead;thread_write *pThreadWrite;
};
#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);pShareMsg = new struct msg_struct;pMutex = new QMutex;pThreadRead  = new thread_read(pShareMsg,pMutex);pThreadWrite = new thread_write(pShareMsg,pMutex);pThreadWrite->start();pThreadRead->start();
}Widget::~Widget()
{delete ui;
}

在这里插入图片描述

  1. 信号和槽
  • 在一个线程中定义一个信号,然后将其连接到另一个线程中的槽函数,通过信号的触发来调用槽函数。这是Qt中最常用的线程间通信方法。
  • 这之中有一个线程铁定是GUI线程。才可以使用信号和槽
  • 例如
    在这里插入图片描述
    输出为
    在这里插入图片描述
  • 值得注意的是不要在GUI程序中加入sleep睡眠之类的代码,容易造成程序崩溃。

3.线程间同步

  • 线程同步是指在多线程环境中,协调线程之间的执行顺序和数据共享,确保线程以预期的方式访问共享资源。同步的主要目的是避免竞争条件(race conditions)和数据不一致性。
1.基于互斥量的线程同步QMutex
  1. 互斥量可以保证在任意时刻只有一个线程可以访问共享资源,从而避免竞争条件和数据不一致性。
  2. 定义一把互斥锁
//widget.h
QMutex *pMutex;
//widget.cpp
pMutex = new QMutex;
  1. 上锁,如果互斥量已经被其他线程锁定,当前线程将被阻塞,直到互斥量可用。
pMutex.lock();
  1. 解锁,访问共享资源后,线程需要释放互斥量的锁,以便其他线程可以访问该资源。
pMutex.unlock();
  1. 尝试上锁,函数tryLock()尝试锁定一个互斥量,如果成功锁定就返回true,如果其他线程已经锁定了这个互斥量就返回false,不等待。有参数则等待。
pMutex.try_Lock();//括号内可以有参数,以毫秒为单位,表示最多等待多少毫秒
2. 基于读写锁的线程同步QReadWriteLock
  • 基于读写锁(Read-Write Lock)的线程同步是一种高效的同步机制,适用于读多写少的场景。与互斥锁不同,读写锁允许多个线程同时读取共享资源,但在写入资源时,只允许一个线程进行写操作,这样可以提高程序的并发性能。
  1. 定义一把读写锁
//widget.h
QReadWriteLock *pRWLock;
//Widget.cpp
pRWLock = new QReadWriteLock;
  1. pRWLock.lockForRead();//以只读方式锁定资源,如果有其他线程以写入方式锁定资源,这个函数会被阻塞
  2. pRWLock.lockForWrite();//以写入方式锁定资源,如果其他线程以读或写方式锁定资源,这个函数会被阻塞
  3. pRWLock.unlock();//解锁
  4. 它们可以在前面加上try,如tryLockForRead();表示尝试以读的方式锁上资源,括号内的参数可以表示尝试多少毫秒
3. 基于条件等待的线程同步QWaitCondition
  • QWaitCondition 提供了一种改进的线程同步方法,QWaitCondition 通过与 QMutex QReadWriteLock 结合使用,可以使一个线程在满足一定条件时通知其他多个线程,使其他多个线程及时进行响应,这样比只使用互斥量或读写锁效率要高一些。
  • 定义

QMutex mutex;
QReadWriteLock readWriteLock;
QWaitCondition condition;
  1. bool wait(QMutex *lockedMutex, unsigned long time = ULONG_MAX),释放lockMutex这个互斥信号量。线程进入休眠,等待被唤醒,默认无限等待。若被唤醒则返回true;若超时则返回false。
  2. bool wait(QReadWriteLock *lockedReadWriteLock, unsigned long time = ULONG_MAX),释放lockedReadWriteLock这个读写锁,并让线程进入等待状态直到被唤醒或者超时。默认情况下,无限期等待。若被唤醒则返回true;若超时则返回false。
  3. void wakeAll():唤醒所有处于等待状态的线程。唤醒顺序不确定,由操作系统的调度策略决定。
  4. void wakeOne():唤醒一个处于等待状态的线程。具体唤醒哪个线程不确定,由操作系统的调度策略决定。
4. 基于信号量的线程同步
  • 信号量(QSemaphore)是用于控制多个线程对共享资源的访问的同步原语。它是一种计数器,允许你在特定时间允许多个线程同时访问某个资源。信号量可以用来限制访问的线程数。
  1. 使用方法
方法名描述参数返回值
构造函数
QSemaphore(int initialCount = 1, int maxCount = 1)创建一个信号量,初始计数和最大计数。initialCount:初始计数值
maxCount:最大计数值
基本方法
acquire(int num = 1)获取 num 个资源,若资源不足,线程阻塞。num:需要获取的资源数量
release(int num = 1)释放 num 个资源,增加信号量的计数器。num:需要释放的资源数量
带超时的方法
acquire(int num, unsigned long timeout = ULONG_MAX)获取 num 个资源,直到超时。num:需要获取的资源数量
timeout:超时时间(毫秒)
bool:成功获取资源返回 true,超时返回 false
检查方法
tryAcquire(int num = 1)尝试获取 num 个资源,若资源不足则立即返回。num:需要获取的资源数量bool:成功获取资源返回 true,否则返回 false
available() const返回可用资源的数量。int:可用资源数量
其他方法
setCount(int count)设置信号量的计数器值。count:新的计数值
maximumCount() const返回信号量的最大值。int:最大值
currentCount() const返回当前信号量的计数值。int:当前计数值
  1. 代码示例
#include <QCoreApplication> // 引入Qt核心应用程序模块
#include <QThread>          // 引入Qt线程模块
#include <QSemaphore>       // 引入Qt信号量模块
#include <QDebug>           // 引入Qt调试输出模块// 创建一个信号量,初始计数为3,表示最多同时允许3个线程访问资源
QSemaphore semaphore(3);class Worker : public QThread {
public:void run() override { // 重写QThread的run()方法,定义线程执行的代码// 尝试在1000毫秒内获取一个资源if (semaphore.tryAcquire(1, 1000)) { // 尝试获取一个资源,如果在超时内未能获取,则返回falseqDebug() << "Thread" << QThread::currentThreadId() << "acquired a resource."; // 打印线程获取资源的消息QThread::sleep(2); // 模拟工作,线程休眠2秒qDebug() << "Thread" << QThread::currentThreadId() << "finished working."; // 打印线程完成工作的消息semaphore.release(); // 释放一个资源,使其他等待的线程可以获取到资源} else {qDebug() << "Thread" << QThread::currentThreadId() << "could not acquire a resource within timeout."; // 打印超时未获取资源的消息}// 显示信号量的状态qDebug() << "Current available resources:" << semaphore.available(); // 打印当前可用资源的数量semaphore.setCount(5); // 修改信号量的计数器值为5,增加可用资源qDebug() << "Max count:" << semaphore.maximumCount(); // 打印信号量的最大计数值qDebug() << "Current count:" << semaphore.currentCount(); // 打印当前信号量的计数值}
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv); // 创建Qt应用程序实例// 创建多个Worker线程实例Worker worker1, worker2, worker3, worker4, worker5;// 启动线程worker1.start();worker2.start();worker3.start();worker4.start();worker5.start();// 等待所有线程完成worker1.wait();worker2.wait();worker3.wait();worker4.wait();worker5.wait();return a.exec(); // 进入Qt事件循环
}

QT睡眠程序

  • 用于让当前线程休眠或延迟执行
  1. QThread::sleep(int sec);//个方法使当前线程休眠指定的秒数。
  2. QThread::msleep(int msec);//这个方法使当前线程休眠指定的毫秒数。
  3. QThread::usleep(int usec);//这个方法使当前线程休眠指定的微秒数。

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

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

相关文章

BGP选路之AS-PATH

原理概述 当一台BGP路由器中存在多条去往同一目标网络的BGP路由时&#xff0c;BGP协议会对这些BGP路由的属性进行比较&#xff0c;以确定去往该目标网络的最优BGP路由。首先要比较的属性是 Preferred Value&#xff0c;然后是Local Preference&#xff0c;再次是路由生成方式&a…

BGP选路之Next Hop

原理概述 当一台BGP路由器中存在多条去往同一目标网络的BGP路由时&#xff0c;BGP协议会对这些BGP路由的属性进行比较,以确定出去往该目标网络的最优BGP路由,然后将该最优BGP路由与去往同一目标网络的其他协议路由进行比较&#xff0c;从而决定是否将该最优BGP路由放进P路由表中…

【在Linux世界中追寻伟大的One Piece】Linux进程概念

目录 1 -> 冯诺依曼体系结构 2 -> 操作系统(operator System) 2.1 -> 概念 2.2 -> 系统调用和库函数 3 -> 进程 3.1 -> 概念 3.2 -> 进程-PCB 3.3 -> 进程状态 3.3.1 -> Z(Zombie)-僵尸进程 3.3.2 -> 孤儿进程 3.4 -> 进程优先级 …

2024-07-24 buildroot c语言应用获取 kernel kobject_uevent_env 发送的消息,侦测USB口变化。

一、kobject_uevent_env 是 Linux 内核中的一个函数&#xff0c;用于发送内核事件到用户空间。它主要用于生成和发送与内核对象&#xff08;kobject&#xff09;相关的事件通知&#xff0c;这些事件通常用于通知用户空间程序&#xff08;如 udev&#xff09;有关硬件的变化或其…

git的一些使用技巧(git fetch 和 git pull的区别,git merge 和 git rebase的区别)

最近闲来无聊&#xff0c;虽然会使用git操作&#xff0c;但是 git fetch 和 git pull 的区别&#xff0c;git merge 和 git rebase的区别只是一知半解&#xff0c;稍微研究一下&#xff1b; git fetch 和 git pull 的区别 git fetch git fetch 是将远程仓库中的改动拉到本地…

解决vscode+UE5中vscode无法识别头文件,无法函数无法跳转,也无法自动补全的问题。

一、概述 接上一条博客&#xff0c;虽然解决了报错的问题&#xff0c;但是实际上的问题却没有解决&#xff0c;无论我怎么点击&#xff0c;其都无法完成跳转&#xff0c;也无法完成自动补全的问题。 在网络上搜索了很多资料后&#xff0c;发现是在使用vscode时候UE5在vscode中的…

百度秋招提前批C++

1.C++内存模型 堆栈全常代 (1)堆 heap : 由malloc分配的内存块,其释放编译器不去管,由我们程序自己控制(一个malloc对应一个free)。涉及的问题:“缓冲区溢出”、“内存泄露”(new分配的在自由存储区 经常由堆实现) (2)栈 stack : 是那些编译器在需要时分配,在…

手动搭建微型计算机(涉及:CPU、内存、寄存器等)

目录 微型计算机基础元件及作用CPU地址总线数据总线 内存地址总线数据总线内存大小的计算 寄存器先将Z80CPU与TC5517内存相连参考文章 微型计算机基础元件及作用 CPU、内存、I/O CPU 包含地址总线引脚和数据总线引脚。 以Z80CPU为例&#xff1a; 地址总线 地址总线引脚…

【React】条件渲染:深入探讨高效开发技巧与最佳实践

文章目录 一、什么是条件渲染&#xff1f;二、条件渲染的实现方式三、条件渲染的最佳实践四、复杂条件渲染的实现 在现代前端开发中&#xff0c;React 已成为开发者构建用户界面的首选框架之一。React 的强大之处在于其组件化和状态管理能力&#xff0c;而条件渲染则是 React 开…

IGV.js | 载入自己下载的gtf文件

1.安装 htslib-1.20 https://www.htslib.org/doc/tabix.html J3$ cd ~/Downloads/ $ wget https://github.com/samtools/htslib/releases/download/1.20/htslib-1.20.tar.bz2 $ tar jxvf htslib-1.20.tar.bz2编译安装&#xff1a; $ cd htslib-1.20/ $ ./configure --prefix/…

java面向对象进阶进阶篇--《抽象类和抽象方法》

个人主页VON 所属专栏java从入门到起飞 目录 个人主页​编辑我的主页​编辑 一、简介 抽象方法&#xff1a; 抽象类&#xff1a; 概述&#xff1a; 二、抽象类 特点和用途 示例&#xff1a; Animal类 Dog类 Flog类 Sheep类 Text类 结果展示&#xff1a; 三、抽象方…

SQL

SQL全称 Structured Query Language&#xff0c;结构化查询语言。操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据库统一标准 。 SQL通用语法 SQL语句可以单行或多行书写&#xff0c;以分号结尾。SQL语句可以使用空格/缩进来增强语句的可读性。MySQL数据库的…

Linux环境下安装配置jdk和maven

一、jdk下载 Oracle的JDK开始收费了&#xff0c;如非必要&#xff0c;请勿使用&#xff01;&#xff01;&#xff01; jdk下载地址1&#xff08;推荐&#xff09;https://github.com/graalvm/graalvm-ce-builds/releases jdk下载地址2&#xff08;可选&#xff09;&#xff1a;…

Mac安装Hoomebrew与升级Python版本

参考 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 安装了Python 3.x版本&#xff0c;你可以使用以下命令来设置默认的Python版本&#xff1a; # 首先找到新安…

防火墙——网络环境支持

目录 网络环境支持 防火墙的组网 web连接上防火墙 web管理口 让防火墙接到网络环境中 ​编辑 管理员用户管理 缺省管理员 接口 配置一个普通接口 创建安全区域 路由模式 透明模式 混合模式 防火墙的安全策略 防火墙转发流程 与传统包过滤的区别 创建安全策略 …

神经网络新范式——LNDP:可终身学习的自主发育程序

近年来人工智能的高速发展离不开深度神经网络的应用&#xff0c;深度神经网络的发展是从大数据和硬件算力设备大规模发展之后才逐渐占据了人工智能的核心研究地位的&#xff0c;在此之前人工智能的研究都是以可解释性强、计算力小的统计学模型为主&#xff0c;但是以统计学为主…

c生万物系列(封装)

为了对c语言进行封装&#xff0c;笔者参考了lw_oopc等开源库&#xff0c;决定使用宏对结构体进行封装。 先说一下大致思想&#xff1a;通过宏&#xff0c;结构体和文件来实现封装。 大概步骤&#xff1a;抽象出类-> 使用lw_oopc库进行封装->定义接口封装底层实现 ->…

【概率论】-2-概率论公理(Axioms of Probability)

上一篇文章我们学习了基本的概率论内容-排列组合&#xff0c;本次我们学习概率论公理的内容&#xff0c;正式开始计算概率&#xff0c;在开始前我们需要学习一些基本概念。 目录 一.样本空间和事件 1.样本空间 2.事件 3.交并补 二、概率公理 1.基本公理 2.对称差 2.布尔…

【Docker】Docker-consul容器服务自动发现与注册

目录 一.Consul概述 1.解决了什么问题 2.什么叫微服务或者注册与发现 3.consul的模式 4.相关命令 二.consul 部署 1.consul服务器部署 2.部署docker容器 3.Nginx负载均衡器 3.1.安装启动nginx 3.2.配置nginx负载均衡 3.3.创建配置consul complate模板文件 3.4.添加…

【Gitlab】SSH配置和克隆仓库

生成SSH Key ssh-keygen -t rsa -b 4096 私钥文件: id_rsa 公钥文件:id_rsa.pub 复制生成的ssh公钥到此处 克隆仓库 git clone repo-address 需要进行推送和同步来更新本地和服务器的文件 推送更新内容 git push <remote><branch> 拉取更新内容 git pull &…