Qt ModbusSlave多线程实践总结

最近项目中用到了ModbusSlave,也就是Modbus从设备的功能,之前用的基本都是master设备,所以读取数据啥的用单线程就行了,用

 void WaitHelper::WaitImplByEventloop(int msec)
{QEventLoop loop;QTimer::singleShot(msec, &loop, &QEventLoop::quit);  // 设置定时器,在超时时退出事件循环loop.exec();  // 进入事件循
}

这种方法进行流程等待也没啥问题。但是在slave模式下,使用这种模式就会造成事件无法正常回调,在等待过程中没法回复请求,导致master设备卡死,最终使用多线程解决的该问题。
这里遵循Qt多线程最佳实践,使用worker->moveToThread(workerThread);实现多线程功能。核心方法就是创建ModbusWorker实例并且移动到QThread中。

bool ModbusTcpSlave::connectToHost()
{worker = new ModbusWorker();workerThread = new QThread(this);worker->moveToThread(workerThread);connect(workerThread, &QThread::started, [=]() {worker->startMonitoring(_obj["address"].toString());});connect(worker, &ModbusWorker::dataWritten, this, &ModbusTcpSlave::onDataWritten);connect(workerThread, &QThread::finished, worker, &QObject::deleteLater);connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater);workerThread->start();return true;
}

然后就是调用方法时使用QMetaObject::invokeMethod异步调用

void ModbusTcpSlave::WriteRegister(int address, int value)
{// 异步跨线程调用QMetaObject::invokeMethod(worker,"setData",Qt::QueuedConnection,Q_ARG(QModbusDataUnit::RegisterType, QModbusDataUnit::HoldingRegisters),Q_ARG(int, address),Q_ARG(quint16, value));
}

以下是源码:

#ifndef MODBUSWORKER_H
#define MODBUSWORKER_H#include <QObject>
#include <QModbusTcpServer>
#include <QModbusDataUnit>class ModbusWorker : public QObject
{Q_OBJECTpublic:explicit ModbusWorker(QObject *parent = nullptr);~ModbusWorker();bool connectToHost(const QString &address);void startMonitoring(const QString &address);void stopMonitoring();public slots:bool setData(QModbusDataUnit::RegisterType table, int address, quint16 value);signals:void dataWritten(QModbusDataUnit::RegisterType table, int address, quint16 value);private slots:void onDataWritten(QModbusDataUnit::RegisterType table, int address, int size);void onStateChanged(QModbusDevice::State state);private:QModbusTcpServer *_modbusServer;
};#endif // MODBUSWORKER_H
#include <QUrl>
#include <QDebug>
#include "modbusworker.h"ModbusWorker::ModbusWorker(QObject *parent) : QObject(parent), _modbusServer(new QModbusTcpServer(this))
{qRegisterMetaType<QModbusDataUnit::RegisterType>("QModbusDataUnit::RegisterType");QObject::connect(_modbusServer, &QModbusTcpServer::stateChanged, this, &ModbusWorker::onStateChanged);QObject::connect(_modbusServer, &QModbusTcpServer::dataWritten, this, &ModbusWorker::onDataWritten);
}ModbusWorker::~ModbusWorker()
{_modbusServer->disconnectDevice();
}bool ModbusWorker::setData(QModbusDataUnit::RegisterType table, int address, quint16 value)
{return _modbusServer->setData(table,address,value);
}void ModbusWorker::onDataWritten(QModbusDataUnit::RegisterType table, int address, int size)
{if(size==1){quint16 value;_modbusServer->data(table, address, &value);emit dataWritten(table,address,value);}
}void ModbusWorker::onStateChanged(QModbusDevice::State state)
{qDebug()<<__FUNCTION__<<__LINE__<<state;
}bool ModbusWorker::connectToHost(const QString &address)
{const QUrl url = QUrl::fromUserInput(address);_modbusServer->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());_modbusServer->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());// 设置Modbus数据单元,类型为保持寄存器QModbusDataUnitMap reg;reg.insert(QModbusDataUnit::HoldingRegisters, {QModbusDataUnit::HoldingRegisters, 0, 30});reg.insert(QModbusDataUnit::InputRegisters, {QModbusDataUnit::InputRegisters, 0, 10});_modbusServer->setMap(reg);_modbusServer->setServerAddress(1);// 初始化保持寄存器的值for (int i = 0; i < 10; ++i) {_modbusServer->setData(QModbusDataUnit::HoldingRegisters, i, 0);}return _modbusServer->connectDevice();
}void ModbusWorker::startMonitoring(const QString &address)
{if(connectToHost(address)){return;}
}void ModbusWorker::stopMonitoring()
{_modbusServer->disconnectDevice();
}```cpp
#ifndef MODBUSTCPSLAVE_H
#define MODBUSTCPSLAVE_H#include <QObject>
#include <QModbusTcpServer>
#include "basecommunication.h"
#include "modbusworker.h"class ModbusTcpSlave : public BaseCommunication
{Q_OBJECT
public:Q_INVOKABLE explicit ModbusTcpSlave(QObject *parent = nullptr);signals:public slots:// BaseCommunication interface
public:virtual bool connectToHost() override;virtual bool isConnected() override;virtual bool disConnectFromHost() override;void WriteRegister(int address, int value);void WriteInputRegister(int address, int value);signals:void dataWritten(QModbusDataUnit::RegisterType,int address, quint16 val);private slots:void onDataWritten(QModbusDataUnit::RegisterType table, int address, int value);private:QThread *workerThread;ModbusWorker *worker;
};#endif // TCPMODBUSSERVER_H
#include <QUrl>
#include "modbustcpslave.h"ModbusTcpSlave::ModbusTcpSlave(QObject *parent) : BaseCommunication(parent)
{
}bool ModbusTcpSlave::connectToHost()
{worker = new ModbusWorker();workerThread = new QThread(this);worker->moveToThread(workerThread);connect(workerThread, &QThread::started, [=]() {worker->startMonitoring(_obj["address"].toString());});connect(worker, &ModbusWorker::dataWritten, this, &ModbusTcpSlave::onDataWritten);connect(workerThread, &QThread::finished, worker, &QObject::deleteLater);connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater);workerThread->start();return true;
}bool ModbusTcpSlave::isConnected()
{return true;
}bool ModbusTcpSlave::disConnectFromHost()
{worker->stopMonitoring();return true;
}void ModbusTcpSlave::WriteRegister(int address, int value)
{// 异步跨线程调用QMetaObject::invokeMethod(worker,"setData",Qt::QueuedConnection,Q_ARG(QModbusDataUnit::RegisterType, QModbusDataUnit::HoldingRegisters),Q_ARG(int, address),Q_ARG(quint16, value));
}void ModbusTcpSlave::WriteInputRegister(int address, int value)
{QMetaObject::invokeMethod(worker,"setData",Qt::QueuedConnection,Q_ARG(QModbusDataUnit::RegisterType, QModbusDataUnit::InputRegisters),Q_ARG(int, address),Q_ARG(quint16, value));
}void ModbusTcpSlave::onDataWritten(QModbusDataUnit::RegisterType table, int address, int value)
{emit dataWritten(table,address,value);
}

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

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

相关文章

opencv--图像

像素(像素点) 定义&#xff1a; Pixel 是 Picture Element&#xff08;图像元素&#xff09;的缩写&#xff0c;是数字图像中最小的独立单位。每个像素代表图像中的一个点的颜色和亮度信息。 关键特性&#xff1a; 颜色&#xff1a;通过不同的色彩模型&#xff08;如RGB、CMYK…

记录学习汇编语言02+各种寄存器分类

8086cpu是十六位的 然后寄存器能存八位 所以分为高八位低八位 高八位在下面低八位在上面 从下往上读&#xff08;从地址小的地方开始读&#xff09; 8086cpu种有两个和栈相关的寄存器 栈段寄存器ss&#xff08;栈顶的段寄存器&#xff09; 栈顶指针寄存器sp&#xff08;…

OpenCV 图形API(53)颜色空间转换-----将 RGB 图像转换为灰度图像函数RGB2Gray()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从 RGB 色彩空间转换为灰度。 R、G 和 B 通道值的常规范围是 0 到 255。生成的灰度值计算方式如下&#xff1a; dst ( I ) 0.299 ∗ src…

(51单片机)LCD显示数据存储(DS1302时钟模块教学)(LCD1602教程)(独立按键教程)(延时函数教程)(I2C总线认识)(AT24C02认识)

目录 演示视频&#xff1a; 源代码 main.c LCD1602.c LCD1602.h AT24C02.c AT24C02.h Key.c Key.h I2C.c I2C.h Delay.c Delay.h 代码解析与教程&#xff1a; Dealy模块 LCD1602模块 Key模块 I2C总线模块 AT24C02模块 /E2PROM模块 main模块 演示视频&#xff1a; E2…

电子病历高质量语料库构建方法与架构项目(数据遗忘篇)

引言 在人工智能与医疗健康的深度融合时代,医疗数据的价值与风险并存。跨机构和平台的医疗数据共享对于推动医学研究、提高诊断精度和实现个性化治疗至关重要,但同时也带来了前所未有的隐私挑战。先进的AI技术可以从理论上去标识化的医疗扫描中重新识别个人身份,例如从MRI数…

CentOS创建swap内存

服务器版本为CentOS7 一、检查现有 swap 空间 sudo swapon --show如果系统中没有 swap 空间或者现有的 swap 空间不足&#xff0c;可以继续后续步骤来创建 swap 空间。 二、创建 swap 文件&#xff08;推荐 2GB 作为示例&#xff09; sudo dd if/dev/zero of/swapfile bs1M …

在Android中如何使用Protobuf上传协议

在 Android 中使用 Protobuf&#xff08;Protocol Buffers&#xff09;主要分为以下几个步骤&#xff1a; ✅ 1. 添加 Protobuf 插件和依赖 在项目的 build.gradle&#xff08;Project 级&#xff09;文件中添加 Google 的 Maven 仓库&#xff08;通常默认已有&#xff09;&am…

Android学习总结之ANR问题

一、ANR 基础概念与核心原理&#xff08;必考题&#xff09; 1. 什么是 ANR&#xff1f;为什么会发生 ANR&#xff1f; 答案要点&#xff1a; 定义&#xff1a;ANR&#xff08;Application Not Responding&#xff09;即应用无响应&#xff0c;是 Android 系统检测到主线程&…

视频监控从安装到优化的技术指南,视频汇聚系统EasyCVR智能安防系统构建之道

在当今数字化安防时代&#xff0c;监控系统的安装与配置对于保障各类场所的安全起着至关重要的作用。从前期规划到实际安装&#xff0c;再到后期的功能实现与维护&#xff0c;每一个环节都不容小觑。本文将详细阐述监控安装过程中的关键要点&#xff0c;并结合EasyCVR平台功能&…

如何避免IDEA每次打开新项目都重复配置Maven?

每次打开新项目都要重新设置Maven路径&#xff1f;每次导入工程都要手动调整settings.xml&#xff1f;如果你也受够了IDEA这种“健忘”行为&#xff0c;那么这篇文章就是为你准备的&#xff01;今天我们就来彻底解决这个问题&#xff0c;让IDEA记住你的Maven配置&#xff0c;一…

PostgesSQL外部数据封装FDW

PostgesSQL外部数据封装FDW 1. FDW外部数据配置&#xff08;单表&#xff09;1.1 远端数据库创建测试表1.2 安装扩展postges\_fdw1.3 创建外部服务SERVER1.4 创建用户映射USER MAPPING1.5 创建远程表FOREIGN TABLE1.6 数据库更新测试 2. FDW外部数据配置&#xff08;用户&#…

策略模式(Strategy Pattern)详解

文章目录 1. 什么是策略模式&#xff1f;2. 为什么需要策略模式&#xff1f;3. 策略模式的核心概念3.1 策略&#xff08;Strategy&#xff09;3.2 具体策略&#xff08;Concrete Strategy&#xff09;3.3 上下文&#xff08;Context&#xff09; 4. 策略模式的结构5. 策略模式的…

在 Vue3 中封装的 Axios 实例中,若需要为部分接口提供手动取消请求的功能

核心思路 封装接口时返回 Promise 和 abort 方法&#xff1a; 为需要支持取消的接口返回一个对象&#xff0c;包含 promise 和 abort 方法&#xff0c;用户可通过 abort 主动中断请求。使用 AbortController 或 CancelToken&#xff1a; 推荐 AbortController&#xff08;浏览…

Flink介绍——实时计算核心论文之Dataflow论文详解

引入 在过去的几篇文章里&#xff0c;我们看到了大数据的流式处理系统是如何一步一步进化的。从最早出现的S4&#xff0c;到能够做到“至少一次”处理的Storm&#xff0c;最后是能够做到“正好一次”数据处理的MillWheel。我们会发现&#xff0c;这些流式处理框架&#xff0c;…

Python自动化解决滑块验证码的最佳实践

1. 引言&#xff1a;滑块验证码的挑战与自动化需求 滑块验证码&#xff08;Slider CAPTCHA&#xff09;是当前互联网广泛使用的反爬机制之一&#xff0c;它要求用户手动拖动滑块到指定位置以完成验证。这种验证方式可以有效阻止简单的自动化脚本&#xff0c;但对爬虫开发者来说…

路由与OSPF学习

【路由是跨网段通讯的必要条件】 路由指的是在网络中&#xff0c;数据包从源主机传输到目的主机的路径选择过程。 路由通常涉及以下几个关键元素&#xff1a; 1.路由器&#xff1a;是一种网络设备&#xff0c;负责将数据包从一个网络传输到另一个网络。路由器根据路由表来决定…

(done) 吴恩达版提示词工程 5. 推理 (情绪分类,控制输出格式,输出 JSON,集成多个任务,文本主题推断和索引,主题内容提醒)

url: https://www.bilibili.com/video/BV1Z14y1Z7LJ?spm_id_from333.788.videopod.episodes&vd_source7a1a0bc74158c6993c7355c5490fc600&p2 别人的笔记 url: https://zhuanlan.zhihu.com/p/626966526 5. 推理任务&#xff08;Inferring&#xff09; 这个视频是关于…

MySQL VS SQL Server:优缺点全解析

数据库选型、企业协作、技术生态、云数据库 1.1 MySQL优缺点分析 优点 开源免费 社区版完全免费&#xff0c;适合预算有限的企业 允许修改源码定制功能&#xff08;需遵守GPL协议&#xff09; 跨平台兼容性 支持Windows/Linux/macOS&#xff0c;适配混合环境部署 云服务商…

Pycharm 代理配置

Pycharm 代理配置 文章目录 Pycharm 代理配置1. 设置系统代理1.1 作用范围1.2 使用场景1.3 设置步骤 2. 设置 python 运行/调试代理2.1 作用范围2.2 使用场景2.3 设置步骤 Pycharm 工具作为一款强大的 IDE&#xff0c;其代理配置在实际开发中也是必不可少的&#xff0c;下面介绍…

maven打包时配置多环境参数

1. pom配置 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.…