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.pswp.cn/news/903097.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903097.shtml
英文地址,請注明出處:http://en.pswp.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.…