十三、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.mzph.cn/news/709085.shtml

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

相关文章

网络工程师笔记5

TCP/IP 常见协议 应用层 Telnet 数据网络中提供远程登录服务的标准协议23FTP 传输文件协议21&#xff0c;20HTTP 超文本传输协议80TFTPSNMPSMTPDNSDHCP 传输层 TCPUDP 网络层 ICMPIGMPIP 数据链路层 PPPOE Internet PPP 传输层 传输层协议接收…

【重要公告】BSV区块链协会宣布将启动多项动态安全增强措施

​​发表时间&#xff1a;2024年2月16日 2024年2月16日&#xff0c;瑞士楚格 - BSV区块链协议的管理机构BSV区块链协会&#xff08;以下简称“BSV协会”&#xff09;宣布对其运营模式实施全新的安全架构&#xff0c;其中包括引入网络访问规则和数字资产找回协议&#xff0c;以及…

密码学在 Web3 钱包中的应用:私钥是什么?bitget钱包为例

在非对称加密演算法中&#xff0c;私钥是一串随机生成的数字&#xff0c;通常以十六进制数表示&#xff08;也就是由0、1、2、3、4、5、6、7、8、9、a、b、c、d、e和f组成&#xff09;。私钥生成后&#xff0c;这串数字被作为一个单向数学函数中的输入值&#xff0c;计算产生的…

YAML管理接口框架配置的最佳实践

管理接口框架配置是构建强大的接口测试框架的关键一环。良好的配置管理可以提高测试效率、可维护性和可扩展性。在本文中&#xff0c;我们将重点介绍使用YAML&#xff08;YAML Ain’t Markup Language&#xff09;来管理接口框架配置的最佳实践&#xff0c;并通过实例演示其用法…

第七十天 APP攻防-微信小程序解包反编译数据抓包APK信息资源提取

第70天 APP攻防-微信小程序&解包反编译&数据抓包&APK信息资源提取 知识点&#xff1a; 0、APK信息资源提取 1、微信小程序致据抓包 2、做信小程序解包反编译 1、信息收集应用8资产提取&权限等 2、漏润发现-反编泽&脱壳&代码审计 3、安全评估组件8散密…

ctfshow——反序列化

文章目录 web 254——啥也没web 255——反序列化对变量进行赋值&#xff08;1&#xff09;web 256——反序列化对变量进行赋值&#xff08;2&#xff09;web 257——对象注入web 258——对象注入(绕过preg_match)web 259 web 254——啥也没 这里就是使用GET传输&#xff0c;use…

SpringMVC02、什么是SpringMVC

2、什么是SpringMVC 2.1、概述 Spring MVC是Spring Framework的一部分&#xff0c;是基于Java实现MVC的轻量级Web框架。 查看官方文档&#xff1a;Web on Servlet Stack 我们为什么要学习SpringMVC呢? Spring MVC的特点&#xff1a; 轻量级&#xff0c;简单易学高效 , 基…

(C语言)Sleep函数,system函数,数组练习,详解与运用

一维数组详解&#xff1a;http://t.csdnimg.cn/zahZF 二维数组详解&#xff1a;http://t.csdnimg.cn/h2mLe 我们看过可一维数组与二维数组&#xff0c;现在我们来进行简单的练习。 题目&#xff1a;编写代码&#xff0c;演⽰多个字符从两端移动&#xff0c;向中间汇聚 1. …

如何使用Windows系统电脑无公网ip远程桌面Ubuntu系统

文章目录 前言1. ubuntu安装VNC2. 设置vnc开机启动3. windows 安装VNC viewer连接工具4. 内网穿透4.1 安装cpolar【支持使用一键脚本命令安装】4.2 创建隧道映射4.3 测试公网远程访问 5. 配置固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址5.3 测试…

QT Widget: 自定义Widget组件及创建和使用动静态库

学习自定义Widget组件&#xff0c;书中的案例&#xff1a; // 自定义QmyBattery组件 // QmyBattery.c #include "qmybattery.h"QmyBattery::QmyBattery(QWidget *parent) : QWidget(parent) {}/** 1.QPainter的viewport()与window()分别代表着物理坐标与逻辑坐标区域…

Topaz DeNoise AI:一键让照片重获清晰 mac/win激活版

Topaz DeNoise AI是一款革命性的图片降噪软件&#xff0c;它利用先进的人工智能算法&#xff0c;帮助用户轻松去除照片中的噪点&#xff0c;恢复图像的清晰度和细节。无论是专业摄影师还是摄影爱好者&#xff0c;Topaz DeNoise AI都能成为他们处理图片时的得力助手。 Topaz De…

57.仿简道云公式函数实战-文本函数-REPT

1. REPT函数 将文本重复一定次数。 2. 函数用法 REPT(text, number_times) 3. 函数示例 将文本重复一定次数。 text: 必需。需要重复显示的文本。 Number_times: 必需。用于指定文本重复次数的正数。 4. 代码实战 首先我们在function包下创建text包&#xff0c;在text…

Win UI3开发笔记(四)设置主题续

上文讲到过关于界面和标题栏以及普通文本的主题设置&#xff0c;这篇说一下关于对话框的主题设置。 我最终没找到办法&#xff0c;寻求办法的朋友可以不用接着看了&#xff0c;以下只是过程。 一个对话框包括标题部分、内容部分和按钮部分&#xff0c;其中&#xff0c;在Cont…

ISP代理是什么?跨境账号养号为什么要选择它?

在跨境出海业务中&#xff0c;代理IP对于您的在线任务至关重要&#xff0c;尤其是对于那些运行多个帐户的人来说。为您的帐户选择正确类型的代理对于确保帐户安全非常重要&#xff0c;劣质的IP容易使账号遭受封号风险。IPFoxy的多种代理IP类型应用范围各有侧重&#xff0c;其中…

Android Stdio Execution failed for task ‘:app:compileDebugKotlin‘ 报错解决

具体报错信息如下&#xff1a; compileDebugJavaWithJavac task (current target is 1.8) and compileDebugKotlin task (current target is 17)jvm target compatibility should be set to the same Java version.很显然&#xff0c;这是一个版本冲突问题&#xff0c;compile…

字符函数和字符串函数(C语言进阶)(三)

目录 前言 接上篇&#xff1a; 1.7 strtok 1.8 strerror 1.9 字符分类函数 总结 前言 C语言中对字符和字符串的处理是很频繁的&#xff0c;但是c语言本身是没有字符串类型的&#xff0c;字符串通常放在常量字符串中或着字符数组中。 字符串常量适用于那些对它不做修改的字…

安卓开发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;验证环…

Java多线程算法总结

1. 标题三个线程同时运行&#xff0c;依次打印ABC&#xff0c;一共打印10次 算法代码如下&#xff1a; public class ThreadTest {private Object oa new Object();private Object ob new Object();private Object oc new Object();private static final String TAG &quo…

【精选】Java项目介绍和界面搭建——拼图小游戏 中

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

LeetCode 刷题 [C++] 第148题.排序链表

题目描述 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 题目分析 根据题意&#xff0c;可以使用归并排序来对链表进行排序。归并排序是基于分治的思想&#xff0c;比较容易实现的就是自顶向下的递归方式来实现。 先找出链表的中点&#x…