当前位置: 首页 > news >正文

十三、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");
}

在这里插入图片描述

相关文章:

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

一、多线程程序 QThread类提供了管理线程的方法&#xff1a;一个对象管理一个线程一般从QThread继承一个自定义类&#xff0c;重载run函数 1、实现程序 &#xff08;1&#xff09;创建项目&#xff0c;基于QDialog &#xff08;2&#xff09;添加类&#xff0c;修改基于QThr…...

今日话题:---自卑

自卑是一种普遍存在的心理现象&#xff0c;它可能源于个人对自身能力、外貌、社会地位等方面的不满意或不自信。自卑感可能会导致消极的情绪和行为&#xff0c;如焦虑、抑郁、逃避现实等。然而&#xff0c;适度的自卑感也可能激发个人努力提升自己&#xff0c;从而实现自我成长…...

Unity 预制体与变体

预制体作用&#xff1a; 更改预制体&#xff0c;则更改全部的以预制体复制出的模型。 生成预制体&#xff1a; 当你建立好了一个模型&#xff0c;从层级拖动到项目中即可生成预制体。 预制体复制模型&#xff1a; 将项目中的预制体拖动到层级中即可复制。或者选择物体复制粘贴。…...

leetcode:860.柠檬水找零

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

Python程序的流程

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 年轻是我们唯一拥有权利去编制梦想的时…...

C语言可以干些什么?C语言主要涉及哪些IT领域?

C语言可以干些什么&#xff1f;C语言主要涉及哪些IT领域&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家…...

element-ui附件上传及在线查看详细总结,后续赋源码

一、附件上传 1、在element-ui上面复制相应代码 a、accept"image/*,.pdf,.docx,.xlsx,.doc,.xls" 是规定上传文件的类型&#xff0c;若是不限制&#xff0c;可以直接将accept‘all即可&#xff1b; b、:action"action" 这个属性就是你的上传附件的地址&am…...

投标中excel表格常用功能梳理

投标中excel表格常用功能梳理&#xff1a; 1.投标报价调整报价的办法&#xff1a; 目的调整报价&#xff0c;把“红框”的报价增加30%&#xff0c;50% 增加30%的步骤&#xff1a; 步骤1&#xff1a;选择1.3 复制&#xff08;ctrlc&#xff09; 步骤2&#xff1a;选择性黏贴 …...

C++二叉搜树的实现(递归和非递归)

目录 1.什么是二叉搜索树 2.二叉搜索树的查找 3.二叉搜索树插入 4.二叉搜索树的删除 1.删除的节点只有左子树或者右子树 2.删除节点左右子树都有的情况 5.代码 1.什么是二叉搜索树 左节点的值小于根节点 右节点大于根节点 左右子树也满足上面两个条件 例&#xff1a;…...

蓝桥杯算法 一.

分析&#xff1a; 本题记录&#xff1a;m个数&#xff0c;异或运算和为0&#xff0c;则相加为偶数&#xff0c;后手获胜。 分析&#xff1a; 369*99<36500&#xff0c;369*100>36500。 注意&#xff1a;前缀和和后缀和问题...

如何学习自然语言处理之语言模型

自然语言处理&#xff08;NLP&#xff09;是一种人工智能技术&#xff0c;它使计算机能够理解和处理人类语言。而语言模型是NLP中的一个重要概念&#xff0c;主要是用来估测一些词的序列的概率&#xff0c;即预测p(w1, w2, w3 … wn)&#xff0c;其中一个应用就是句子的生成。 …...

Zoho ToDo 满足您的需求:任务管理满足隐私和安全要求

任务管理工具已经成为我们日常生活中不可或缺的一部分&#xff0c;它们帮助我们处理各种事务&#xff0c;从杂项和愿望清单到管理截止日期和资源。这些工具不仅仅是简单的任务列表&#xff0c;它们掌握了项目的蓝图、雄心勃勃的目标和完成的最后期限。然而随着这些工具的使用越…...

仿牛客网项目---社区首页的开发实现

从今天开始我们来写一个新项目&#xff0c;这个项目是一个完整的校园论坛的项目。主要功能模块&#xff1a;用户登录注册&#xff0c;帖子发布和热帖排行&#xff0c;点赞关注&#xff0c;发送私信&#xff0c;消息通知&#xff0c;社区搜索等。这篇文章我们先试着写一下用户的…...

虚拟机部署Sentry步骤,国内地址

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…...

[Android View] 可绘制形状 (Shape Xml)

一切以官方文档为主 官方文档https://developer.android.com/guide/topics/resources/drawable-resource?hlzh-cn#Shape 什么是可绘制形状 可以理解为用xml文件来描述一个简单的Drawable图形&#xff0c;比如说以下这段xml就可以用来描述一个白色的圆形&#xff1a; <?…...

[游戏开发][虚幻5]新建项目注意事项

鼠标右键点击Client.uproject文件&#xff0c;可以看到三个比较关键的选项&#xff0c; 启动游戏&#xff0c;生成sln解决方案&#xff0c;切换引擎版本 断点调试 C代码重要步骤 如果你想断点调试C代码&#xff0c;则必须使用使用代码编译启动引擎&#xff0c;你需要做几个操作…...

防考试作弊切屏

防考试作弊切屏 方法一&#xff1a;监听页面失焦聚焦事件&#xff1a;防止任何操作 监听考试页面失焦事件记录切出时间页面聚焦时累积记录切入时间&#xff0c;累积时间大于1分钟自动交卷并移除时间页面销毁移出事件***bug&#xff1a;必须把事件回调定义为方法&#xff0c;在…...

浅析能耗监测系统在大型数据中心的应用

彭姝麟 Acrelpsl 1总体设计 大型数据中心能耗监测系统包含硬件和软件两大部分&#xff0c;其硬件组成主要包括监控服务器、主机设备、网络设备、环境参数传感器、通风模块等&#xff0c;总体采集逻辑采用三级监控体系。一级为主机设备&#xff0c;作为系统的应用层&#xff0c…...

robotframework-去除字符串左侧的0的方法

参考文章&#xff1a;https://www.cnblogs.com/xiaodouzhou-123/p/10333759.html...

【Linux C | 网络编程】getaddrinfo 函数详解及C语言例子

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...