【QT5】<重点> QT多线程

文章目录

前言

一、QThread创建多线程

二、QMutex基于互斥量的同步

三、QReadWriteLock线程同步

四、QWaitCondition线程同步

五、QSemaphore基于信号量的同步


前言

本篇记录学习QT多线程的知识,参考视频13.1QThread创建多线程程序_哔哩哔哩。若涉及版权问题,请联系作者删除!


一、QThread创建多线程

1. 使用步骤:

  • ①创建的类需要继承QThread类。
  • ②重写run函数,新建的线程会执行run函数。
  • ③线程开启:对象调用start方法,使线程执行run函数。
  • ④线程终止:
    • 对象调用terminate方法,提示线程不再执行run函数。
    • 对象调用wait方法,等待线程执行完毕。
  • ⑤线程销毁:动态申请new需要调用deleteLater方法销毁线程对象。(该函数可以放置于run函数内,当run函数执行完毕后就会销毁该线程对象,防止内存泄漏)注意:尽量少用静态申请栈空间的方式创建线程对象,因为很可能该对象销毁时线程仍在执行,就会报错。

2. 案例演示:创建一个类继承QThread,在重写的run方法中根据是否暂停来随机生成骰子值。

【1】实现效果:

【2】dicethread.h:

#ifndef DICETHREAD_H
#define DICETHREAD_H#include <QThread>class DiceThread : public QThread
{Q_OBJECTpublic:DiceThread();~DiceThread();private:void run() override;signals:void diceGenerate(int diceCount, int diceValue);private slots:void stopDiceThread_slot();void startGenerate_slot();void pauseGenerate_slot();private:int diceCount = 0;  //第几次生成骰子int diceValue = 1;  //骰子的值bool pauseFlag = true;  //暂停生成骰子bool stopFlag = true;   //线程结束标志
};#endif // DICETHREAD_H

【3】dicethread.cpp:

#include "dicethread.h"
#include <QRandomGenerator>DiceThread::DiceThread()
{}DiceThread::~DiceThread()
{}/* 线程执行函数 */
void DiceThread::run()
{stopFlag = false;while (!stopFlag) {if (!pauseFlag) {diceValue = QRandomGenerator::global()->bounded(1, 7);emit diceGenerate(++diceCount, diceValue);}msleep(500);}
}/* 接收到线程终止信号 */
void DiceThread::stopDiceThread_slot()
{stopFlag = true;
}/* 接收到开始生成信号 */
void DiceThread::startGenerate_slot()
{pauseFlag = false;
}/* 接收到停止生成信号 */
void DiceThread::pauseGenerate_slot()
{pauseFlag = true;
}

【4】widget.h:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "dicethread.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();signals:void stopDiceThread();  //线程停止,DiceThread内部修改标志位void startGenerate();   //开始生成,DiceThread内部修改标志位void pauseGenerate();   //暂停生成,DiceThread内部修改标志位private slots:void on_btnStartThread_clicked();void diceGenerate_slot(int, int);//接收DiceThread的骰子信息void on_btnStopThread_clicked();void on_btnDiceBegin_clicked();void on_btnDiceEnd_clicked();void on_btnClearText_clicked();private:Ui::Widget *ui;DiceThread *dice = nullptr;
};
#endif // WIDGET_H

【5】widget.cpp:

#include "widget.h"
#include "ui_widget.h"
#include <QString>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置按钮互斥ui->btnStartThread->setEnabled(true);ui->btnStopThread->setEnabled(false);ui->btnDiceBegin->setEnabled(false);ui->btnDiceEnd->setEnabled(false);
}Widget::~Widget()
{delete ui;
}/* 槽函数:接收diceGenerate信号*/
void Widget::diceGenerate_slot(int diceCount, int diceValue)
{ui->plainTextEdit->appendPlainText("第" + QString::number(diceCount) + "次,生成点数为:"+ QString::number(diceValue));
}/* "启动线程"按钮 */
void Widget::on_btnStartThread_clicked()
{//创建DiceThread对象dice = new DiceThread;connect(dice, SIGNAL(diceGenerate(int, int)), this, SLOT(diceGenerate_slot(int, int)));connect(this, SIGNAL(stopDiceThread()), dice, SLOT(stopDiceThread_slot()));connect(this, SIGNAL(startGenerate()), dice, SLOT(startGenerate_slot()));connect(this, SIGNAL(pauseGenerate()), dice, SLOT(pauseGenerate_slot()));//启动线程dice->start();ui->plainTextEdit->appendPlainText("线程已启动");//设置按钮互斥ui->btnStartThread->setEnabled(false);ui->btnStopThread->setEnabled(true);ui->btnDiceBegin->setEnabled(true);ui->btnDiceEnd->setEnabled(false);
}/* "停止线程"按钮 */
void Widget::on_btnStopThread_clicked()
{dice->terminate();dice->wait();dice->deleteLater();ui->plainTextEdit->appendPlainText("线程已停止");emit stopDiceThread();//设置按钮互斥ui->btnStartThread->setEnabled(true);ui->btnStopThread->setEnabled(false);ui->btnDiceBegin->setEnabled(false);ui->btnDiceEnd->setEnabled(false);
}/* "开始"按钮 */
void Widget::on_btnDiceBegin_clicked()
{emit startGenerate();ui->btnDiceBegin->setEnabled(false);ui->btnDiceEnd->setEnabled(true);
}/* "暂停"按钮 */
void Widget::on_btnDiceEnd_clicked()
{emit pauseGenerate();ui->btnDiceBegin->setEnabled(true);ui->btnDiceEnd->setEnabled(false);
}/* "清空"按钮 */
void Widget::on_btnClearText_clicked()
{ui->plainTextEdit->clear();
}

二、QMutex基于互斥量的同步

1. 背景:当多个线程同时访问一块内存区域时,就会出现错误,因此需要线程同步。

2. QMutex:在互斥量之前上锁,然后在一个线程使用完互斥量之后解锁。如果一个线程试图向一个已经被其它线程上锁的互斥量上锁的话,这个线程将被阻塞,直到这个互斥量被解锁。

3. 基本使用:

  • lock():上锁
  • unlock():解锁
  • tryLock():尝试上锁,若成功则上锁,不成功则返回false

4. 案例演示: 

创建两个线程来同时访问value,通过查看相关调试信息来获取是哪个线程修改了value的值。我们是想让两个线程交叉着访问value。

【1】不加锁的代码:

#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>class MyThread : public QThread
{Q_OBJECTpublic:MyThread();void run() override;void setNum(int *num);private:int *num;
};#endif // MYTHREAD_H
#include "mythread.h"MyThread::MyThread()
{}void MyThread::run()
{while (*num > 0) {(*num)--;qDebug("线程号: %d, value = %d", QThread::currentThreadId(), *num);}
}void MyThread::setNum(int *num)
{this->num = num;
}

#include "widget.h"
#include <QApplication>
#include "mythread.h"int main(int argc, char *argv[])
{int value = 20;MyThread thread1, thread2, thread3;thread1.setNum(&value);thread2.setNum(&value);thread3.setNum(&value);thread1.start();thread2.start();thread3.start();while (1) {}return 0;
}

从运行结果中,我们能够看出value递减打印出现问题,这不是我们想要的

【2】使用QMutex后:就不会出现上述的问题。


三、QReadWriteLock线程同步

1. 说明:使用互斥量时存在一个问题,每次只能有一个线程获得互斥量的权限。如果多个线程读取某个变量,就会出现排队现象。而实际上,有需求让多个线程同时读取。因此,引入QReadWriteLock实现线程同步。

2. 主要函数:

  • lockForRead():只读方式锁定资源,如果有其他线程以写入方式锁定,这个函数会阻塞。
  • lockForWrite():以写入方式锁定资源,如果其他线程以读或写模式锁定资源,则函数堵塞。
  • unlock():解锁。
  • tryLockForRead():是lockForRead的非阻塞版本。
  • tryLockForWrite():是lockForWrite的非阻塞版本。

四、QWaitCondition线程同步

1. 说明:在著名的“生产者-消费者”模型中,生产者负责制作蛋糕,消费者负责拿走蛋糕。此时,生产者制作蛋糕完成后应该通知消费者,因此引入QWaiteCondition实现线程同步,需要搭配QMutex锁。

2. 常用函数:

  • wait(QMutex *lockedMutex):进入等待状态,解锁互斥量lockedMutex,被唤醒后锁定lockedMutex并退出函数。
  • wakeAll():唤醒所有处于等待状态的线程,唤醒顺序不确定。
  • wakeOne():唤醒一个处于等待状态的线程,唤醒哪个不确定。

五、QSemaphore基于信号量的同步

1. 说明:信号量和互斥量的区别在于,信号量可以被多个线程同时访问,而互斥量只能被一个线程访问。同时,在“生产者-消费者”模型中,可能会有多个生产者生产蛋糕,生产者最多可以容纳10个蛋糕,然后消费者在蛋糕生产出来后就可以拿走。因此,引入QSemaphore实现基于信号量的线程同步。

2. 注意:

  • QSemaphore 类中的信号量实际上是一个计数器,它用于记录能够同时访问某个共享资源的线程数。

3. 常用函数:

  • acquire(int n):尝试获得n个资源,如果不够将堵塞线程,直到n个资源可用。调用后,信号量计数器-1.
  • release(int n):释放资源,如果资源已经全部可用,则可扩充资源总数。调用后,信号量计数器+1.
  • int available():返回当前信号量的资源个数。
  • bool tryAcquire(int n=1):尝试获取n个资源,不成功时,不阻塞线程。

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

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

相关文章

单元测试很难么?

前言 你可能会用单元测试框架&#xff0c;python的unittest、pytest&#xff0c;Java的Junit、testNG等。 那么你会做单元测试么&#xff01;当然了&#xff0c;这有什么难的&#xff1f; test_demo.py def inc(x): return x 1 def test_answer(): assert inc(3) 4 i…

经验分享,CRC(循环冗余校验)在线计算

这里分享一个好用的在线计算CRC的网站。 网址&#xff1a;http://www.ip33.com/crc.html 截图&#xff1a;

Ubuntu22.04系统安装及配置

文章目录 一、选择“安装” 二、选择“语言” 三、安装器更新 四、键盘布局 五、选择安装类型 六、网络配置 七、代理设置 八、镜像地址 九、磁盘划分 十、设置用户名、主机名、登录密码 十一、升级到Ubuntu Pro 十二、SSH设置 十三、选装软件包 十四、开始安装进…

灰度图像直方图均衡化

文章目录 1.实验目的2.需求3.代码4.实验结果 1.实验目的 了解一种最基本的图像增强技术&#xff0c;本质上是对灰度图像进行灰度变换。 2.需求 对给定图像进行灰度直方图展示&#xff0c;然后均衡化后再次展示 3.代码 import cv2 as cv import numpy as np from matplotli…

类注释规范

类注释规范 1.1.1 模板配置 模板路径&#xff1a;File–>settings–>Editor–>File and Code Templates–>Includes–>File Header  N A M E &#xff1a;设置类名&#xff0c;与下面的 {NAME}&#xff1a;设置类名&#xff0c;与下面的 NAME&#xff1a;设…

【TB作品】MSP430G2553,单片机,口袋板, 多路温度巡回检测仪的设计

题7 多路温度巡回检测仪的设计 设计一个多路温度检测仪&#xff0c;共有8个测温点&#xff0c;每个点连续检测8次&#xff0c;以平均值代表该点温度&#xff0c;并轮流在LED显示器上显示。测试检测元件为铂热电阻Pt1000, 温度测量范围为100℃ ——500℃&#xff0c;测量精度为1…

Pointnet++改进即插即用系列:全网首发HeatBlock高计算效率和全局接受野|即插即用,提升特征提取模块性能

简介:1.该教程提供大量的首发改进的方式,降低上手难度,多种结构改进,助力寻找创新点!2.本篇文章对Pointnet++特征提取模块进行改进,加入HeatBlock,提升性能。3.专栏持续更新,紧随最新的研究内容。 目录 1.理论介绍 2.修改步骤 2.1 步骤一 2.2 步骤二 2.3 步骤三 1.…

Jlink下载固件到RAM区

Jlink下载固件到RAM区 准备批处理搜索exe批处理调用jlink批处理准备jlink脚本 调用执行 环境&#xff1a;J-Flash V7.96g 平台&#xff1a;arm cortex-m3 准备批处理 搜索exe批处理 find_file.bat echo off:: 自动识别脚本名和路径 set "SCRIPT_DIR%~dp0" set &qu…

【0008day】Shiny的介绍

介绍&#xff1a;Shiny 是一个开源 R 包&#xff0c;它提供了一个优雅而强大的 Web 框架&#xff0c;用于使用 R 构建 Web 应用程序。Shiny 可以帮助您将分析转变为交互式 Web 应用程序&#xff0c;而无需 HTML、CSS 或 JavaScript 知识。 # download R package pkgtest <-…

计算机体系结构期末复习(一二章)

计算机体系结构期末复习&#xff08;一二章&#xff09; 由于内容比较多&#xff0c;分为两次发出 注意&#xff1a;可能有部分考点遗漏&#xff0c;可能有部分例题没有匹配正确的知识点或被遗漏&#xff0c;欢迎各位补充 第一章 1. 计算机系统的层次性 知识点&#xff1a…

实验室自用LabVIEW软件与商用软件价格差异分析

实验室自用LabVIEW软件与商用软件在价格上的差异源于功能与扩展包、技术支持与服务、使用场景与合规性、更新与维护、市场与定价策略、培训与教育资源及许可证管理与合规审计等方面的不同。商用软件提供更全面的功能和支持&#xff0c;确保高可靠性和合规性&#xff0c;因此价格…

奥特曼谈AI的机遇、挑战与人类自我反思:中国将拥有独特的大语言模型

奥特曼在对话中特别提到&#xff0c;中国将在这个领域扮演重要角色&#xff0c;孕育出具有本土特色的大语言模型。这一预见不仅彰显了中国在全球人工智能领域中日益增长的影响力&#xff0c;也预示着未来技术发展的多元化趋势。 ①奥特曼认为AI在提升生产力方面已显现积极作用&…

APP自动化测试-Appium常见操作之详讲

一、基本操作 1、点击操作 示例&#xff1a;element.click() 针对元素进行点击操作 2、初始化&#xff1a;输入中文的处理 说明&#xff1a;如果连接的是虚拟机&#xff08;真机无需加这两个参数&#xff0c;加上可能会影响手工输入&#xff09;&#xff0c;在初始化配置中…

JupyterLab使用指南(六):JupyterLab的 Widget 控件

1. 什么是 Widget 控件 JupyterLab 中的 Widget 控件是一种交互式的小部件&#xff0c;可以用于创建动态的、响应用户输入的界面。通过使用 ipywidgets 库&#xff0c;用户可以在 Jupyter notebook 中创建滑块、按钮、文本框、选择器等控件&#xff0c;从而实现数据的交互式展…

多态性(Java)

本篇学习面向对象语言的第三个特性——多态。 目录 1、多态的概念 2、继承多态实现条件 3、重写 4、重新与重载的区别&#xff1a; 5、向上转移和向下转型 5、1向上转型&#xff1a; 5、2 向下转型 1、多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态…

互联网应用主流框架整合之构建REST风格的系统

REST&#xff08;Representational State Transfer&#xff09;&#xff0c;中文译为“表述性状态转移”&#xff0c;是由Roy Fielding博士在他的博士论文中提出的一种软件架构风格&#xff0c;特别适用于网络应用的设计。REST不是一个标准&#xff0c;而是一种设计原则和约束集…

【CSS in Depth2精译】1.1.4 源码顺序

解决层叠冲突的最后一环叫做 源码顺序&#xff0c;有时又称为 出现顺序&#xff08;order of appearance&#xff09;。如果其他判定规则均一致&#xff0c;则样式表中后出现的、或者在页面较晚引入的样式表声明&#xff0c;将最终胜出。 也就是说&#xff0c;可以通过控制源码…

textarea标签改写为富文本框编辑器KindEditor

下载 - KindEditor - 在线HTML编辑器 KindEditor的简单使用-CSDN博客 一、 Maven需要的依赖&#xff1a; 如果依赖无法下载&#xff0c;可以多添加几个私服地址&#xff1a; 在Maven框架中加入镜像私服 <mirrors><!-- mirror| Specifies a repository mirror site to…

免费定位服务方案:华为定位+天地图逆地理编码实现位置信息查询

对于Android开发来说进行定位开发时会使用以下几个产品 高德定位sdk百度定位sdk腾讯定位sdk 由于这几款产品在商用时需要支付相应的费用&#xff0c;如果不使用这几款产品又该如何定位呢&#xff1f; 有一种解决方案就是 华为定位天地图逆地理编码实现位置信息查询 通过 华…