Qt多线程问题3:基于线程同步实现生产者消费者模型

之前自己写了一个收数据的功能,但是没有数据的时候就要不停监听,那监听多久合适呢?1ms ?10 ms ? 100ms?但是你也不确定数据什么时候来,那么就可以使用经典的生产者消费者模型。这次的实验中我参考了人民邮电出版社<<Qt5.9 C++开发指南>>中的实现。

原书中的实现,将锁和同步量声明为全局变量,并不是很优雅。我们可以实现一个管理类, 将锁和同步量写在管理类里边,管理类管理生产者和消费者,生产者和消费者都可以看到管理类内的互斥量和同步量,代码结构如下:

管理类ThreadManager

头文件的声明如下:

#ifndef THREADMANAGER_H
#define THREADMANAGER_H#include <QMutex>
#include <QObject>
#include <QThread>
#include <QSharedPointer>
#include <QScopedPointer>
#include <QMutexLocker>
#include <QWaitCondition>
#include <ProducerThread.h>
#include <ConsumerThread.h>class ThreadManager: public QObject
{Q_OBJECT
public:ThreadManager();void initConnections();void start();private:QSharedPointer<QMutex>              m_mutex;QSharedPointer<QWaitCondition>      m_waitCondition;QScopedPointer<ProducerThread>      m_producer;QScopedPointer<ConsumerThread>      m_consumer;
};#endif // THREADMANAGER_H

因为互斥量mutex是不支持赋值的,所以可以用共享指针给管理起来,然后在生产者和消费者线程中都声明同样的共享指针,指向同一个互斥量和同步量。.cpp实现如下:

#include "ThreadManager.h"ThreadManager::ThreadManager(): m_consumer(new ConsumerThread(this)), m_producer(new ProducerThread(this)), m_mutex(new QMutex), m_waitCondition(new QWaitCondition)
{m_producer->setSharedMutex(m_mutex);m_producer->setSharedCondition(m_waitCondition);m_consumer->setSharedMutex(m_mutex);m_consumer->setSharedCondition(m_waitCondition);initConnections();
}void ThreadManager::initConnections()
{connect(m_producer.data(), &ProducerThread::sendData,m_consumer.data(), &ConsumerThread::comsumeData);
}void ThreadManager::start()
{m_consumer->start();m_producer->updateStopState(true);m_producer->start();
}

函数的其他说明:构造函数, m_producer与m_consumer, 都设置好互斥量和同步量的共享指针;initConnections(): 连接生产者与消费者;start():模拟启动。

生产者ProducerThread

声明如下:

#ifndef PRODUCERTHREAD_H
#define PRODUCERTHREAD_H#include <QSharedPointer>
#include <QWaitCondition>
#include <QThread>
#include <QDebug>
#include <QMutexLocker>class ProducerThread: public QThread
{Q_OBJECT
public:explicit ProducerThread(QObject *parent);void updateStopState(bool state) {m_state = state;}void setSharedMutex(QSharedPointer<QMutex> point);void setSharedCondition(QSharedPointer<QWaitCondition> point);private:bool                                m_state;int                                 m_startVal;QSharedPointer<QMutex>              m_mutex;QSharedPointer<QWaitCondition>      m_waitCondition;protected:void run() override;signals:void sendData(int val);
};#endif // PRODUCERTHREAD_H

函数说明:updateStopState():决定是否继续发数据;setSharedMutex()和setSharedContition(),给成员变量m_mutex以及m_waitCondition赋值,指向管理者的互斥量与同步量;定义好signal,sendData()用来发送数据。.cpp实现如下:

#include "ProducerThread.h"
#include "ThreadManager.h"ProducerThread::ProducerThread(QObject *parent): m_state(false), m_startVal(0)
{
}void ProducerThread::setSharedMutex(QSharedPointer<QMutex> point)
{m_mutex = point;
}void ProducerThread::setSharedCondition(QSharedPointer<QWaitCondition> point)
{m_waitCondition = point;
}void ProducerThread::run()
{while(m_state) {QMutexLocker lock(m_mutex.data());qDebug() << "Send Data: " << QString::number(m_startVal);emit sendData(m_startVal++);lock.unlock();m_waitCondition->wakeOne();QThread::sleep(2);}
}

在run()函数中,不停加锁再发数据,发数据后用wakeOne()唤醒正在阻塞的消费者,然后中间间隔2s。

消费者ConsumerThread

#ifndef CONSUMERTHREAD_H
#define CONSUMERTHREAD_H#include <QDebug>
#include <QThread>
#include <QMutexLocker>
#include <QSharedPointer>
#include <QWaitCondition>class ConsumerThread: public QThread
{Q_OBJECT
public:explicit ConsumerThread(QObject *parent);void updateState(bool state) {m_state = state;}void setSharedMutex(QSharedPointer<QMutex> point);void setSharedCondition(QSharedPointer<QWaitCondition> point);private:bool                                m_state;int                                 m_data;QSharedPointer<QMutex>              m_mutex;QSharedPointer<QWaitCondition>      m_waitCondition;protected:void run() override;public slots:void comsumeData(int val);
};#endif // CONSUMERTHREAD_H

逻辑基本和生产者一样,定义好槽函数,用来处理数据即可。

#include "ConsumerThread.h"
#include "ThreadManager.h"ConsumerThread::ConsumerThread(QObject *parent): m_state(true)
{
}void ConsumerThread::setSharedMutex(QSharedPointer<QMutex> point)
{m_mutex = point;
}void ConsumerThread::setSharedCondition(QSharedPointer<QWaitCondition> point)
{m_waitCondition = point;
}void ConsumerThread::comsumeData(int val)
{m_data = val;
}void ConsumerThread::run()
{while(m_state) {QMutexLocker lock(m_mutex.data());m_waitCondition->wait(m_mutex.data());qDebug() << "Consume Data: " << m_data;lock.unlock();}
}

run()中的部分比较重要,现加锁,再通过wait解锁,等待唤醒,得到数据就打印。

主函数

#include "mainwindow.h"
#include <QDebug>
#include <QApplication>
#include "ThreadManager.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;// w.show();ThreadManager manager;manager.start();qDebug() << "Finished!";return a.exec();
}

通过manager.start()开始模拟,执行结果如下:

OK,模拟完毕!!

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

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

相关文章

CentOS7.9 Nginx + EMQX集群组建 MQTTS平台

前面我们有介绍过单机版EMQX的安装 CentOS7 安装 EMQX&#xff08;MQTT&#xff09;&#xff0c;今天我们来讲一下实际项目里用的到MQTTS平台。 一、EMQX单机配置 简单部署两个节点&#xff0c;修改对应配置文件 (/usr/local/emqx/etc/emqx.conf) 中的node内容&#xff1a; nam…

sqllab第十八关通关笔记

知识点&#xff1a; UA注入 不进行url解析&#xff0c;不能使用 %20 编码等操作出现在User-agent字段中一般为insert语句 insert 表名(字段1&#xff0c;字段2&#xff0c;。。。) values(数据1&#xff0c;数据2&#xff0c;。。。) 通过admin admin进行登录发现页面打印出了…

【投稿优惠-EI稳定检索】2024年图像处理与机械系统工程国际学术会议 (ICIPMSE 2024)

【投稿优惠-EI稳定检索】2024年图像处理与机械系统工程国际学术会议 (ICIPMSE 2024) 大会主题: (主题包括但不限于, 更多主题请咨询会务组苏老师) 图像处理 基于图像的渲染 计算机视觉 可视化分析 模式识别 3D打印 渲染和动画 渲染技术 电脑动画 基于草图的建模 机械…

Spring boot创建第一个项目

作者简介&#xff1a; zoro-1&#xff0c;目前大二&#xff0c;正在学习Java&#xff0c;数据结构&#xff0c;spring等 作者主页&#xff1a; zoro-1的主页 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f496; Spring boot创建第一个项目 sp…

ELK日志管理实现的3种常见方法

ELK日志管理实现的3种常见方法 1. 日志收集方法 1.1 使用DaemonSet方式日志收集 通过将node节点的/var/log/pods目录挂载给以DaemonSet方式部署的logstash来读取容器日志,并将日志吐给kafka并分布写入Zookeeper数据库.再使用logstash将Zookeeper中的数据写入ES,并通过kibana…

TSINGSEE青犀AI烟火识别等算法打造电瓶车消防安全解决方案

一、背景分析 根据国家消防救援局的统计&#xff0c;2023年全国共接报电动自行车火灾2.1万起&#xff0c;相比2022年上升17.4%&#xff0c;电动自行车火灾安全隐患问题不容忽视。 电瓶车火情主要问题和原因&#xff1a; 电瓶车/电池质量良莠不齐用户安全意识薄弱&#xff0c…

增删卜易——八宫六十四卦

之前看倪海厦的《天纪》笔记里面提到了六十四卦世应,觉得不知道这个世应是啥意思。很长时间就没看了,偶然间看到了张文江教授写的一本书《潘雨廷先生谈话录》提到了《卜筮正宗》,“卜筮最后的判断是非理性转义,其他一切都只是形式”,“明人的著作,从京氏易出,如今天几日…

应用案例 | 基于三维机器视觉的自动化码垛解决方案

Part.1 行业背景 通过显扬科技三维机器视觉设备&#xff0c;搭配三维视觉分析系统&#xff0c;实现码垛的智能化升级&#xff0c;早期使用机器人码垛采用机械臂和简单的控制系统&#xff0c;码垛能力和效率较低。随着现代工业的发展&#xff0c;机器人码垛也开始采用先进的传感…

数据分析-Pandas多维数据平行坐标可视化

数据分析-Pandas多维数据平行坐标可视化 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据表…

《ElementPlus 与 ElementUI 差异集合》el-input 多包裹一层 el-input__wrapper

差异 element-ui el-input 中&#xff0c;<div class"el-input"> 下一级就是 <input> 标签 &#xff1b;element-plus el-input中&#xff0c;<div class"el-input"> 和 <input> 标签之间多了一层 <div class"el-input__…

opencv中的图像均值模糊—blur

平均模糊是通过对图像的每个像素及其周围像素的值求平均来实现的。 blur函数通过计算输入图像image中每个像素及其邻域内像素的平均值来工作。 // 图像卷积 void QuickDemo::Conv_image_demo(Mat &image) {Mat dst;blur(image, dst, Size(3, 3), Point(-1, -1));// Point(…

【论文阅读】MSGNet:学习多变量时间序列预测中的多尺度间序列相关性

MSGNet&#xff1a;学习多变量时间序列预测中的多尺度间序列相关性 文献介绍摘要总体介绍背景及当前面临的问题现有解决方案及其局限性本文的解决方案及其贡献 背景知识的相关工作背景知识问题表述&#xff1a; Method论文主要工作1.输入嵌入和剩余连接 (Input Embedding and R…