十三、Qt多线程与线程安全

news/发布时间2024/9/20 7:56:48

一、多线程程序

QThread类提供了管理线程的方法:
  • 一个对象管理一个线程
  • 一般从QThread继承一个自定义类,重载run函数

1、实现程序

在这里插入图片描述

(1)创建项目,基于QDialog

(2)添加类,修改基于QThread

在这里插入图片描述

#ifndef DICETHREAD_H
#define DICETHREAD_H#include <QThread>class DiceThread : public QThread
{Q_OBJECTprivate:int m_seq = 0;int m_diceValue;bool m_Paused = true;bool m_stop = false;public:explicit DiceThread();void diceBegin();void dicePause();void stopThread();protected:void run() Q_DECL_OVERRIDE;signals:void newValued(int seq, int diceValue);public slots:
};#endif // DICETHREAD_H
#include "dicethread.h"
#include <QTime>DiceThread::DiceThread()
{}void DiceThread::diceBegin()
{m_Paused = false;
}void DiceThread::dicePause()
{m_Paused = true;
}void DiceThread::stopThread()
{m_stop = true;
}void DiceThread::run()
{m_stop = false;m_seq = 0;qsrand(QTime::currentTime().second());while (!m_stop) {if(!m_Paused){m_diceValue = qrand()%6+1;m_seq++;emit newValued(m_seq, m_diceValue);}sleep(1);}quit();
}

(3)实现按钮功能

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :QDialog(parent),ui(new Ui::Dialog)
{ui->setupUi(this);ui->btnStartThread->setEnabled(true);ui->btnStart->setEnabled(false);ui->btnStop->setEnabled(false);ui->btnStopThread->setEnabled(false);connect(&threadA, SIGNAL(started()),this, SLOT(on_threadAStarted()));connect(&threadA, SIGNAL(finished()),this, SLOT(on_threadAFinished()));connect(&threadA, SIGNAL(newValued(int,int)),this, SLOT(on_threadAnewValue(int,int)));
}Dialog::~Dialog()
{delete ui;
}void Dialog::closeEvent(QCloseEvent *event)
{if(threadA.isRunning()){threadA.stopThread();threadA.wait();}event->accept();
}void Dialog::on_btnStartThread_clicked()
{threadA.start();
}void Dialog::on_btnStart_clicked()
{threadA.diceBegin();
}void Dialog::on_btnStop_clicked()
{threadA.dicePause();
}void Dialog::on_btnStopThread_clicked()
{threadA.stopThread();
}void Dialog::on_btnClearText_clicked()
{ui->plainTextEdit->clear();
}void Dialog::on_threadAnewValue(int seq, int diceValue)
{ui->plainTextEdit->appendPlainText(QString::asprintf("第%d次投色子: 点数%d", seq, diceValue));
}void Dialog::on_threadAStarted()
{ui->labelStatus->setText("Thread状态:started");ui->btnStartThread->setEnabled(false);ui->btnStart->setEnabled(true);ui->btnStop->setEnabled(true);ui->btnStopThread->setEnabled(true);
}void Dialog::on_threadAFinished()
{ui->labelStatus->setText("Thread状态:finished");ui->btnStartThread->setEnabled(true);ui->btnStart->setEnabled(false);ui->btnStop->setEnabled(false);ui->btnStopThread->setEnabled(false);
}

在这里插入图片描述

二、互斥量

QMutex和QMutexLocker是基于互斥量的线程同步类
  • QMutex定义的实力是互斥量,主要提供了三个函数
    • lock():锁定互斥量,如果另一个线程锁定了这个互斥量,将阻塞直到另一个解锁
    • unlock():解锁一个互斥量
    • trylock():尝试锁定一个互斥量,如果成功返回true,失败(其他线程已经锁定这个互斥量)返回false,不阻塞线程。
  • QMutexLocker简化了互斥量的处理
    • 构造一个函数接受一个互斥量作为参数,并将其锁定
    • 析构函数解锁该互斥量

1、实现程序

(1)拷贝上一个项目

(2)修改程序为直接读取

void DiceThread::readValue(int *seq, int *diceValue)
{*seq = m_seq;*diceValue = m_diceValue;
}void DiceThread::run()
{m_stop = false;m_seq = 0;qsrand(QTime::currentTime().second());while (!m_stop) {if(!m_Paused){m_diceValue = 50;msleep(50);m_diceValue = qrand();msleep(50);m_diceValue = m_diceValue%6+1;msleep(50);m_seq++;
//            emit newValued(m_seq, m_diceValue);}sleep(1);}quit();
}
void Dialog::on_TimerOut()
{int seq, diceValue;threadA.readValue(&seq, &diceValue);ui->plainTextEdit->appendPlainText(QString::asprintf("第%d次投色子: 点数%d", seq, diceValue));
}

在这里插入图片描述

(3)使用QMutex互斥量

void DiceThread::readValue(int *seq, int *diceValue)
{mMutex.lock();*seq = m_seq;*diceValue = m_diceValue;mMutex.unlock();
}void DiceThread::run()
{m_stop = false;m_seq = 0;qsrand(QTime::currentTime().second());while (!m_stop){if(!m_Paused){mMutex.lock();m_diceValue = 50;msleep(50);m_diceValue = qrand();msleep(50);m_diceValue = m_diceValue % 6 + 1;msleep(50);m_seq++;//            emit newValued(m_seq, m_diceValue);mMutex.unlock();}sleep(1);}quit();
}

在这里插入图片描述

(4)使用QMutexLocker

void DiceThread::readValue(int *seq, int *diceValue)
{QMutexLocker locker(&mMutex);*seq = m_seq;*diceValue = m_diceValue;
}

(5)使用QMutex.trylock

bool DiceThread::readValue(int *seq, int *diceValue)
{//    QMutexLocker locker(&mMutex);if(mMutex.tryLock()){*seq = m_seq;*diceValue = m_diceValue;mMutex.unlock();return true;}return false;
}

三、读写锁

QReadWriteLock提供了以下主要函数:
  • lockForRead():只读方式锁定资源,如果有其他线程以写入方式锁定,这个函数会阻塞
  • lockForWrite():以写入方式锁定资源,如果本线程或者其他线程以读取或写入锁定资源,则函数阻塞
  • unlock():解锁
  • tryLockForRead():是lockForRead非阻塞版本
  • tryLockForWrite():是lockForWrite非阻塞版本
  • 读写锁同样有QReadLocker和QWriteLocker

四、条件变量QWaitCondition

QWaitCondition用于通知其他线程,如接收数据和处理数据之间通知。提供了一些函数:
  • wait(QMutex *lockedMutex):进入等待状态,解锁互斥量lockMutex,被唤醒后锁定lockMutex并退出函数
  • wakeAll():唤醒所有处于等待的线程,线程唤醒的顺序不确定,有操作系统调度策略决定
  • QakeOne():唤醒一个处于等待状态的线程,唤醒哪个线程不确定,由操作系统调度策略决定

1、实现程序

在这里插入图片描述

(1)拷贝上一个项目

(2)使用QWaitCondition设置数据更新

#include "dicethread.h"
#include <QTime>
#include <QWaitCondition>
#include <QMutex>int m_seq = 0;
int m_diceValue;
bool m_stop = false;
QMutex m_Mutex;
QWaitCondition waitCondition;ProducerThread::ProducerThread()
{}void ProducerThread::stopThread()
{m_stop = true;
}void ProducerThread::run()
{m_stop = false;m_seq = 0;qsrand(QTime::currentTime().second());while (!m_stop){m_Mutex.lock();m_diceValue = qrand() % 6 + 1;m_seq++;m_Mutex.unlock();waitCondition.wakeOne();sleep(1);}quit();
}ConsumerThread::ConsumerThread()
{}void ConsumerThread::stopThread()
{m_stop = true;waitCondition.wakeOne(); // 需要给wait置信号,否则阻塞无法结束
}void ConsumerThread::run()
{m_stop = false;while (!m_stop){m_Mutex.lock();waitCondition.wait(&m_Mutex);emit newValued(m_seq, m_diceValue);m_Mutex.unlock();msleep(100);}quit();
}

在这里插入图片描述

五、信号量

QSemaphore信号量通常用于保护一定数量的相同的资源。QSemaphore是实现信号量功能的类,提供了以下函数:
  • acquire(int n):尝试获得n个资源,如果不够将阻塞线程,直到n个资源可用
  • release(int n):释放资源,如果资源已经全部可用,则可扩充资源总数
  • int available():返回房前信号量的资源个数
  • bool tryAcquire(int n=1):尝试获取n个资源,不成功是,不阻塞线程

1、实现程序

在这里插入图片描述

(1)创建项目,基于QDIalog

在这里插入图片描述

(2)创建线程类

(3)使用信号量实现功能

#include "threadtest.h"
#include <QSemaphore>const int bufferSize = 8;
int buffer1[bufferSize] = {0};
int buffer2[bufferSize] = {0};
int curBuf = 1; // 当前采集数据使用的缓冲区QSemaphore semEmptyBufs(2); // 两个资源
QSemaphore semFullBufs;ThreadDAQ::ThreadDAQ()
{}void ThreadDAQ::stopThread()
{m_stop = true;
}void ThreadDAQ::run()
{m_stop = false;int counter = 0;while(!m_stop){semEmptyBufs.acquire();for (int i = 0; i < bufferSize; ++i){if(curBuf == 1){buffer1[i] = counter;}else{buffer2[i] = counter;}counter++;msleep(50);}if(curBuf == 1){curBuf = 2;}else{curBuf = 1;}semFullBufs.release();}exit();
}ThreadShow::ThreadShow()
{}void ThreadShow::stopThread()
{m_stop = true;
}void ThreadShow::run()
{m_stop = false;int seq = 0;while(!m_stop){semFullBufs.acquire();int buf[bufferSize] = {0};if(curBuf == 1){memcpy(buf, buffer2, sizeof(int)*bufferSize);}else{memcpy(buf, buffer1, sizeof(int)*bufferSize);}emit newValue(buf, bufferSize, seq++);semEmptyBufs.release();}exit();
}
#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :QDialog(parent),ui(new Ui::Dialog)
{ui->setupUi(this);ui->btnStopThread->setEnabled(false);connect(&threadConsumer, SIGNAL(newValue(int*, int, int)),this, SLOT(on_threadNewValue(int*, int, int)));connect(&threadProducer, SIGNAL(started()),this, SLOT(on_threadProducer_started()));connect(&threadProducer, SIGNAL(finished()),this, SLOT(on_threadProducer_finished()));connect(&threadConsumer, SIGNAL(started()),this, SLOT(on_threadConsumer_started()));connect(&threadConsumer, SIGNAL(finished()),this, SLOT(on_threadConsumer_finished()));
}Dialog::~Dialog()
{delete ui;
}void Dialog::on_threadNewValue(int *data, int count, int seq)
{QString str = QString::asprintf("第%03d次,内容:", seq);for (int var = 0; var < count; ++var){str += QString::asprintf("%03d ,", data[var]);}ui->plainTextEdit->appendPlainText(str);
}void Dialog::on_btnStartThread_clicked()
{threadConsumer.start();threadProducer.start();ui->btnStartThread->setEnabled(false);ui->btnStopThread->setEnabled(true);
}void Dialog::on_btnStopThread_clicked()
{threadProducer.stopThread();threadConsumer.stopThread();ui->btnStartThread->setEnabled(true);ui->btnStopThread->setEnabled(false);
}void Dialog::on_btnClearText_clicked()
{ui->plainTextEdit->clear();
}void Dialog::on_threadProducer_started()
{ui->labelProducer->setText("Producer线程:started");
}void Dialog::on_threadProducer_finished()
{ui->labelProducer->setText("Producer线程:finished");
}void Dialog::on_threadConsumer_started()
{ui->labelConsumer->setText("Consumer线程:started");
}void Dialog::on_threadConsumer_finished()
{ui->labelConsumer->setText("Consumer线程:finished");
}

在这里插入图片描述

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

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

相关文章

提升智能客服机器人的语义理解能力:理解用户的语义和意图

智能客服机器人的发展已经成为现代服务业的一大亮点。它们不仅能够提供724小时不间断的服务&#xff0c;而且能够处理大量的用户请求&#xff0c;大大提高了服务效率。然而&#xff0c;尽管智能客服机器人的技术已经取得了显著的进步&#xff0c;但其语义理解能力仍有待提高。为…

Crawler爬虫基础知识

本来其实不知道爬虫的意义的&#xff0c;但是发现爬虫在信息收集的那一方面好像挺重要&#xff01;&#xff01; 那么就来浅学一下吧&#xff01;&#xff01;&#xff01; 1.基本的储备 对于爬虫&#xff0c;我们一般都是用的python去编写脚本 &#xff0c;其中还要导入…

阿里云启动实例进入了急救模式解决办法

相关文档 问题描述 通过远程连接软件无法登录Linux实例&#xff0c;通过使用管理终端连接Linux实例远程连接时&#xff0c;发现系统进入到急救模式&#xff08;emergency mode&#xff09;&#xff0c;且出现报错。 CentOS实例报如下错误。 systemctl default to try again…

模拟算法题练习(一)

模拟算法介绍&#xff1a; 模拟算法通过模拟实际情况来解决问题&#xff0c;一般容易理解但是实现起来比较复杂&#xff0c;有很多需要注意的细节&#xff0c;或者是一些所谓很“麻模“的东西。 模拟题一般不涉及太难的算法&#xff0c;一般就是由较多的简单但是不好处理的部…

Java——建造者模式(Builder)

建造者模式&#xff08;Builder&#xff09; 1、建造者模式的定义 将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 Builder模式是一步一步创建一个复杂对象的创建型模式&#xff0c;它允许使用者在不知道内部建造细节的情况下&…

Java版企业电子招标采购系统源码Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis

项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及审…

【计算机】本科考研还是就业?

其实现在很多计算机专业的学生考研&#xff0c;也是无奈的选择 技术发展日新月异&#xff0c;而在本科阶段&#xff0c;大家学着落后的技术&#xff0c;出来找工作自然会碰壁。而且现在用人单位的门槛越来越高&#xff0c;学历默认研究生起步&#xff0c;面试一般都是三轮起步…

Linux 下安装Jupyter

pip3 install jupyter pip3 install ipython -------------------------------------------- pip3 install jupyterlab jupyter lab pip3 list | grep jupyterlab 启动&#xff1a; python3 -m jupyter lab 2.安装朱皮特 pip3 install -i https://pypi.douban.com/simpl…

安卓开发1- android stdio环境搭建

安卓开发1-android stdio环境搭建 Jdk环境搭建 1. 准备Jdk,这边已经准备好了jdk1.8.0,该文件直接使用即可 2. 系统变量添加 %JAVA_HOME%\bin JAVA_HOME 3. 系统变量&#xff0c;Path路径添加 4. 添加完成后&#xff0c;输入命令javac / java -version&#xff0c;验证环…

初学者如何使用QT新建一个包含UI界面的C++项目

文章目录 一、下载并安装QT51、下载安装包2、注册/登录账号3、安装qt6 二、新建QT Widget项目1、新建项目并且运行2、易错点&#xff1a;可能运行成功得到UI界面但是会报错&#xff08;原因是使用了中文路径&#xff09; 一、下载并安装QT5 1、下载安装包 进入下载网址 Windo…

DOM 创建节点、添加节点和删除节点

创建元素节点 document.createElement(‘标签名’) 创建文本节点document.createTextNode ( 内容 ) 根据传入的标签名创建出一个空的元素对象创建出来的默认不显示&#xff0c;要成为别人的子元素才能显示&#xff0c;所以要结合appendChild使用 添加节点&#xff08;后面&am…

使用sunshine和moonlight实现远程游戏串流

过年回家想要打游戏&#xff0c;但是苦于家里没有电脑&#xff0c;又没办法把电脑搬回去&#xff0c;于是想到了使用串流的方式。 实现串流的软件有多种&#xff1a; moonlight。因为仅实现了 NVIDIA 的游戏串流协议&#xff0c;所以只支持 N 卡。Steam Link。支持 steam 的游…

Flutter Text 下划线

IntrinsicWidth(child: Column(mainAxisAlignment:MainAxisAlignment.center,children: [Text("工单名称",style: TextStyle(overflow: TextOverflow.fade,color: AppColors.baseColor,fontSize: 15.sp,// decorationStyle: TextDecorationStyle.dashed),),Container…

Win11系统安装安卓子系统教程

随着Win11系统的不断普及&#xff0c;以及硬件设备的更新换代&#xff0c;我相信很多同学都已经更新并使用到了最新的Win11系统。那么&#xff0c;Win11系统最受期待的功能“Windows Subsystem for Android”&#xff08;简称WSA&#xff09;&#xff0c;即《安卓子系统》。他可…

【MATLAB】MVMD_ MFE_SVM_LSTM 神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 MVMD_MFE_SVM_LSTM神经网络时序预测算法结合了多变量多尺度分解&#xff08;MVMD&#xff09;、多尺度特征提取&#xff08;MFE&#xff09;、支持向量机&#xff08;SVM&#xff09;和长…

(vue)复合型输入框el-input输入数字类型,e,+,-等特殊符号可以输入

(vue)复合型输入框el-input输入数字类型&#xff0c;e&#xff0c;&#xff0c;-等特殊符号可以输入 效果 代码 <el-form-item label"分数区间"><el-inputplaceholder"请输入内容"v-model.number"formInline.scoreIntervalValue"clas…

DolphinScheduler——奇富科技的调度实践

目录 一、技术架构 二、业务挑战 2.1 调度任务量大 2.2 运维复杂 2.3 SLA要求高 三、调度优化实践 3.1 重复调度 3.2 漏调度 3.3 Worker服务卡死 3.4 任务重复运行 四、服务监控 4.1 方法耗时监控 4.2 任务调度链路监控 五、用户收益 原文大佬的这篇调度系统案例…

excel 实现分组排序功能

我们经常会遇到按照分组进行排序&#xff0c;在excel如何实现呢&#xff1f; 如下列的数据&#xff0c;需要按照分组&#xff0c;将得分从高到底排名 我们可以使用如下的公式操作即可实现 SUMPRODUCT((A$2:A$15A2)*(C$2:C$15>C2))1

解读人工智能的理论基石

1956年的一个夏天&#xff0c;在达特茅斯学院的一个小会议室里&#xff0c;一群充满好奇和野心的年轻科学家聚集在一起&#xff0c;他们有一个共同的梦想&#xff1a;创造能够模仿人类智能的机器。这不仅仅是科幻小说的情节&#xff0c;更是人工智能历史上一个真实的起点。从那…

2023 re:Invent 用 Amazon Q 打造你的知识库

前言 随着 ChatGPT 的问世&#xff0c;我们迎来了许多创新和变革的机会。一年一度的亚马逊云科技大会 re:Invent 也带来了许多前言的技术&#xff0c;其中 Amazon CEO Adam Selipsky 在 2023 re:Invent 大会中介绍 Amazon Q 让我印象深刻&#xff0c;这预示着生成式 AI 的又一…
推荐文章