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

一、多线程程序

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.rhkb.cn/news/266912.html

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

相关文章

“环波罗的海”包围圈将正式形成

据“直新闻”的消息称&#xff0c;近日匈牙利国会同意了瑞典加入北约的申请&#xff0c;在走完相关后续程序后&#xff0c;瑞典就将成为北约第三十二个成员国&#xff0c;而北约对俄罗斯打造的“环波罗的海”包围圈也将正式形成&#xff0c;即除俄方外&#xff0c;波罗的海周边…

遥感影像处理(ENVI+ChatGPT+python+ GEE)处理高光谱及多光谱遥感数据

遥感技术主要通过卫星和飞机从远处观察和测量我们的环境&#xff0c;是理解和监测地球物理、化学和生物系统的基石。ChatGPT是由OpenAI开发的最先进的语言模型&#xff0c;在理解和生成人类语言方面表现出了非凡的能力。本文重点介绍ChatGPT在遥感中的应用&#xff0c;人工智能…

111期_C++_2024年1月份作业博客_选择题错题总结

一、野指针问题&#xff1a;在定义的时候没有初始化&#xff0c;就不能能用scanf 或 printf 二、一个变量出现在表达式的两边作为两个不同的操作数&#xff0c; 并且其中一个操作数带有&#xff0c;此时表达式出现歧义 三、两端出栈问题&#xff1a; 错因&#xff1a;未理解题…

力扣SQL50 进店却未进行过交易的顾客 查询

Problem: 1581. 进店却未进行过交易的顾客 文章目录 思路Code 思路 &#x1f468;‍&#x1f3eb; 山山山林老木 左连接查询筛选 transation_id 为 null 的值group by customer_id Code select v.customer_id ,count(customer_id) count_no_trans from Visits v left jo…

java -进行堆转储文件分析

文章目录 前言java -进行堆转储文件分析1. 首先在window上主动生成堆转储文件2. 获取堆转储文件的方式3. 堆转储文件分析 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人…

【24年最新版PythonPycharm安装】保姆级别安装教学!附激活码插件分享~

Python 下载安装 Python可以编译成可执行文件&#xff08;。 py&#xff09;&#xff0c;并通过网络在计算机和其它终端设备上运行。它有内置的数据类型、函数、类和对象&#xff0c;可以将其用于各种目的&#xff0c;例如管理数据和脚本开发。 Python已经成为一种非常流行的…

PyTorch深度学习快速入门

PyTorch深度学习快速入门 1.PyTorch环境配置及安装2.python编辑器的选择、安装、配置&#xff08;pycharm、JupyTer安装&#xff09;3.为什么torch.cuda.is_available()返回false4.python学习中两大法宝函数&#xff08;也可用在pytorch&#xff09;5.pycharm和jupyter&#xf…

论文设计任务书学习文档|基于Vue.js的库存管理系统的设计与实现

文章目录 论文(设计)题目:基于Vue.js的库存管理系统的设计与实现1、论文(设计)的主要任务及目标2、论文(设计)的主要内容3、论文(设计)的基本要求4、进度安排论文(设计)题目:基于Vue.js的库存管理系统的设计与实现 1、论文(设计)的主要任务及目标 基于Vue.js的…

Android Shadow插件化框架分析与集成(一)

一、shadow源码导入及分析 1、下载项目源码 2、导入到Android studio 3、设置jdk及sdk版本 包/应用描述类型sample-constant公共字符串常量libsample-host宿主应用applicationsample-host-lib宿主应用依赖包libsample-manager是插件管理器的动态实现,主要负责加载插件和安装…

【C++】用文件流的put和get成员函数读写文件

题目 编写一个mycopy程序&#xff0c;实现文件复制的功能。用法是在控制台输入&#xff1a; mycooy 源文件名 目标文件名 参数介绍 m a i n main main 函数的参数有两个&#xff0c;一个int类型参数和一个指针数组。 a r g c argc argc 表示参数的个数。参数为void时 a r g …

跨区域复制建筑UI输入框脚本迷你世界

--复制区域文件 --设置坐标起点&#xff0c;终点 --创建区域 --获取坐标id,data --星空露珠工作室制作 local pos1{x-16,y7,z28} local pos2{x28,y44,z-9} local block{num0} local str{} local str0{} local num0 local count0 local ui6 --几个输入框 local romath.random(…

redis-RedisTemplate.opsForGeo 的geo地理位置及实现附近的人的功能

redis内部使用的是 zset 数据结构存储&#xff0c;如下 import cn.huawei.VideoApplication; import cn.huawei.domain.Jingqu; import cn.huawei.service.JingquService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired…

Typora快捷键设置详细教程(内附每个步骤详细截图)

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&#xff1a;程序员洲洲。 &#x1f388; 本文专栏&#xff1a;本文…

leetcode:860.柠檬水找零

题意&#xff1a;按照支付顺序&#xff0c;进行支付&#xff0c;能够正确找零。 解题思路&#xff1a;贪心策略&#xff1a;针对支付20的客人&#xff0c;优先选择消耗10而不是消耗5&#xff0c;因为5可以用来找零10或20. 代码实现&#xff1a;有三种情况&#xff08;代表三种…

蓝桥杯-灌溉

参考了大佬的解题思路&#xff0c;先遍历一次花园&#xff0c;找到所有的水源坐标&#xff0c;把它们存入 “水源坐标清单” 数组内&#xff0c;再读取数组里的水源坐标进行扩散。 #include <iostream> using namespace std; int main() {int n,m,t,r,c,k,ans0,list_i0;…

“内容+科技” 2023爱奇艺拿稳了“高质量增长”指南

“无论影视行业还是互联网行业&#xff0c;最难的时候应该是过去了&#xff0c;接下来我们要高质量增长。” 2023年5月10日&#xff0c;爱奇艺创始人、CEO龚宇在爱奇艺世界大会上给出了这样的判断。大半年之后&#xff0c;爱奇艺公布的2023年全年财报&#xff0c;最终诠释了高…

新闻网站封锁AI爬虫 AI与新闻媒体博弈继续

随着ChatGPT等新兴AI模型的兴起&#xff0c;它们所依赖的网络爬虫正面临来自全球主流新闻网站的大规模封锁。Richard Fletcher博士团队对十个国家主流新闻网站的统计发现&#xff0c;到2023年底&#xff0c;48%的网站屏蔽了OpenAI的爬虫&#xff0c;24%屏蔽了Google的爬虫。那么…

信号系统之快速傅里叶变换

1 使用复数DFT的实数DFT 本文的主题&#xff0c;如何使用 FFT 计算真正的 DFT&#xff1f; 由于 FFT 是一种用于计算复数 DFT 的算法&#xff0c;因此了解如何将实数 DFT 数据输入和输出复数 DFT 格式非常重要。图 12-1 比较了实数 DFT 和复数 DFT 存储数据的方式。实数 DFT …

深度伪造,让网络钓鱼更加难以辨别

网络钓鱼一直是安全领域的一个突出话题&#xff0c;尽管这类诈骗形式已经存在了几十年&#xff0c;依旧是欺诈攻击或渗透组织的最有效方法之一。诈骗分子基于社会工程原理&#xff0c;通过邮件、网站以及电话、短信和社交媒体&#xff0c;利用人性&#xff08;如冲动、不满、好…

【Leetcode】938. 二叉搜索树的范围和

文章目录 题目思路代码结论 题目 题目链接 给定二叉搜索树的根结点 root&#xff0c;返回值位于范围 [low, high] 之间的所有结点的值的和。 示例 1&#xff1a; 输入&#xff1a;root [10,5,15,3,7,null,18], low 7, high 15 输出&#xff1a;32 示例 2&#xff1a; 输入…