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

【QT常用技术讲解】多线程处理+全局变量处理异步事件并获取多个线程返回的结果

前言

       QTableView加入勾选项后(参考【QT常用技术讲解】QTableView添加QCheckBox、QPushButton),如果支持右键菜单功能,此时就有统一执行多个异步事件,并且统一输出到界面的需求了,本篇结合多线程+共享全局变量进行开发。

概述

        QT开发中,单个异步事件处理(比如网络通信ping一个IP,或者是执行一条后台命令后等待返回结果),创建一个线程,并通过connect关联信号和槽,异步获取到一条结果即可,如果是多个同种类型异步事件需要同时处理(比如网络通信ping多个IP,或者是执行多条后台命令后等待返回结果),此时就需要创建多个线程,并且用共享全局变量收集全部结果进行统一处理。

        本篇通过同时开多个线程ping IP,并获取全部结果后,通过对话框展示结果来实现整体功能。

功能详解

1、增加共享全局变量

增加了两个文件:globalvalue.h和globalvalue.cpp,对变量进行声明和定义,代码如下所示:

//globalvalue.h源代码
#ifndef GLOBALVALUE_H
#define GLOBALVALUE_H
#include <QString>
#include <QList>namespace GlobalVariables {//声明全局变量extern QList<QString> g_calbackmsg;
}#endif // GLOBALVALUE_H
//globalvalue.cpp源代码
#include "globalvalue.h"namespace GlobalVariables {//定义全局变量QList<QString> g_calbackmsg;
}

2、改造命令处理模块

原来是单线程时,后台命令处理线程完成任务之后,通过发送信号 emit callback()把结果输出给PING模块即可,而多条命令时,则通过互斥锁+全局共享变量获取返回结果来处理。

    //多线程调用共享变量,需要上互斥锁mutex.lock();//qDebug() << __LINE__ << "add ret:"<<retstr;g_calbackmsg.append(retstr);mutex.unlock();

完整代码如下:

//threadCmd.cpp源代码
#ifndef THREADCMD_CPP
#define THREADCMD_CPP#include "threadCmd.h"
#include <QDebug>
#include <QProcess>
#include "src/util/comm_define.h"
#include <QTextCodec>
//增加全局变量头文件和命名空间,以及互斥锁
#include <QMutex>
#include "src/util/globalvalue.h"
using namespace GlobalVariables;
QMutex mutex;ThreadCmd::ThreadCmd(const QString &param,QObject *parent) : QThread(parent),m_param(param) {}void ThreadCmd::run(){QString retstr="";QProcess process;// 执行命令QString cmd = m_param;//qDebug() << __LINE__ << cmd;process.start(cmd);if(process.waitForFinished()){// 读取进程的输出QString output = QString::fromLocal8Bit(process.readAllStandardOutput());QTextCodec *codec = QTextCodec::codecForName("GBK");QString unicodeOutput = codec->toUnicode(output.toLocal8Bit());//emit callback(unicodeOutput);retstr=QString("[error]:命令[%1]命令执行成功").arg(cmd);}else{// emit callback("[error]:命令执行失败");retstr=QString("[error]:命令[%1]命令执行错误").arg(cmd);}//多线程调用共享变量,需要上互斥锁mutex.lock();//qDebug() << __LINE__ << "add ret:"<<retstr;g_calbackmsg.append(retstr);mutex.unlock();//emit callback(retstr);----多线程用了共享全局变量之后,不需要返回此值// 进程使用完毕后,可以手动删除process.deleteLater();exit(0);
}#endif // THREADCMD_CPP

3、ping模块多线程改造

对按钮事件进行改造,创建多线程之前,通过g_calbackmsg.clear()先请客全局共享变量,创建线程后,增加了多线程列表threadList来启动和删除线程,另外单独增加一个线程来处理结果ThreadDisplaymsg,代码如下所示:

//pingdialog.cpp源代码
void pingDialog::on_start_clicked()
{bool bfind=false;ui->textBrowser->setReadOnly(false);//ui->textBrowser->setText("--------ping start--------");QString times = ui->timeBox->currentText();QString Ipstr=ui->ipEdit->text();//处理多个IP,组装后台执行命令,并调用线程取执行g_calbackmsg.clear();QStringList iplist = Ipstr.split(";");for(int  i=0;i<iplist.size();i++){QString ip=iplist[i];QString cmd = QString("ping -n %1 %2").arg(times).arg(ip);qDebug() << __LINE__ <<"cmd:" <<cmd;//把调用QProcess执行后台命令的代码改成调用多线程类ThreadCmd *thread = new ThreadCmd(cmd, this);//等待多线程的callback信号,关联ThreadsendResult槽函数来处理结果connect(thread, &ThreadCmd::callback, this, &pingDialog::ThreadsendResult);threadList.append(thread);thread->start();bfind = true;}qDebug()<< __LINE__ << __FUNCTION__ << bfind;if(bfind){//创建专门的结果处理线程来弹窗对话框显示结果ThreadDisplaymsg *dthread = new ThreadDisplaymsg(iplist,this);connect(dthread, &ThreadDisplaymsg::callback, this, &pingDialog::DisplayResult);dthread->start();}this->close();}

4、新增结果处理线程ThreadDisplaymsg

增加了两个文件:threadDisplaymsg.h和threadDisplaymsg.cpp,

//threadDisplaymsg.h源代码
#ifndef THREADDISPLAYMSG_H
#define THREADDISPLAYMSG_H#include <QThread>
#include <QString>
#include "src/util/globalvalue.h"  //引用全局变量的头文件
using namespace GlobalVariables;   //声明全局变量的命名空间class ThreadDisplaymsg : public QThread
{Q_OBJECT
public:explicit ThreadDisplaymsg(const QStringList &param,QObject *parent = nullptr) ;protected:void run() override;
signals:void callback(const QString result);
private:QStringList m_paramlist;
};#endif // THREADDISPLAYMSG_H
//threadDisplaymsg.cpp源代码
#ifndef THREADDISPLAYMSG_CPP
#define THREADDISPLAYMSG_CPP#include "threadDisplaymsg.h"
#include <QDebug>
#include <QMessageBox>//传递参数param进来
ThreadDisplaymsg::ThreadDisplaymsg(const QStringList &param,QObject *parent) : QThread(parent),m_paramlist(param) {}void ThreadDisplaymsg::run(){int len = m_paramlist.size();//m_paramlist是IP列表,即IP数量,也等于开启线程的数量//qDebug() << "ThreadDisplaymsg:" <<__LINE__ << len;int loop_num=0;int max_num=100;//如果超过100秒还没获取到结果,说明你要优化的是异步的响应机制,而不是当前的代码,100秒都给不了结果,体验得有多差while(loop_num<max_num){//等待全部的线程返回结果if(g_calbackmsg.size()==len)//结果数量break;loop_num++;QThread::sleep(1);}qDebug() << "ThreadDisplaymsg wait for " <<loop_num << "s";QString result="";for(QString msg : g_calbackmsg) {result += msg;result += "\n";}qDebug() << "=====ThreadDisplaymsg callback=======";//所有的结果累加完成后发送信号callbackemit callback(result);
}#endif // THREADDISPLAYMSG_CPP

5、QTableView表的模块改动

        改动位置是右键菜单功能的信号和槽进行优化,增加了disconnect()来断掉connect()的链接,如下代码,如果注释掉disconnect()功能,每次点击ping功能菜单之后,disconnect()就会累加1,导致对话框弹出N个,不能等系统自动回收,需要disconnect()关掉,并且是在connect()之前关掉,因为多线程是异步的:先connect后disconnect的话,多线程还没返回结果,已经执行disconnect了,这时候connect就被关闭了。

void tab_basemsg::tableWidget_MenuRequested(const QPoint &pos) {QModelIndex index = ui->tableWidget->indexAt(pos);//获取当前行if (!index.isValid()) return;QMenu menu(this);//单选项才有查看详情if(m_iplist.size()<=1){QAction *DiplaymsgAction = menu.addAction(tr("查看详情"));connect(DiplaymsgAction,&QAction::triggered,[=](){//获取选择的单元格QList<QTableWidgetItem *> selected_cells = ui->tableWidget->selectedItems();if(!selected_cells.isEmpty()){QTableWidgetItem *codeCell = ui->tableWidget->item(selected_cells.first()->row(),HEAD_BASEMSG_CODE);if(codeCell!=nullptr){QString code = codeCell->text();stBasemsg basemsg=m_basemsgmap[code];basemsgDialg->setModal(false);basemsgDialg->setWindowTitle("保存");//basemsgDialg->setFixedSize(500,400);basemsgDialg->open();basemsgDialg->init(1,basemsg);basemsgDialg->exec();}}});}QAction *NetpingAction = menu.addAction(tr("Ping此计算机"));connect(NetpingAction,&QAction::triggered,[=](){QString ipstr;for(int  i=0;i<m_iplist.size();i++){QString ip=m_iplist[i];ipstr += ip;if(i!=(m_iplist.size()-1)){ipstr += ";";}}qDebug() << __LINE__ << __FUNCTION__ << ipstr;pingdlg->setIp(ipstr);pingdlg->setModal(false);pingdlg->setWindowTitle("PING测试");pingdlg->setFixedSize(500,400);pingdlg->open();pingdlg->init();pingdlg->exec();// 先断开之前的连接--如果不断开链接,每次操作此功能时,connect都+1,就会出现多次弹窗disconnect(pingdlg, &pingDialog::sendtobasemsg, this, nullptr);//connect要放在disconnect后面:即先关闭上一次的connect,再出现创建connect//因为多线程是异步的:先connect后disconnect的话,多线程还没返回结果,已经执行disconnect了,这时候connect就被关闭了connect(pingdlg,&pingDialog::sendtobasemsg,this,&tab_basemsg::displaysendFileresult);});menu.exec(QCursor::pos());//menu.exec(ui->tableWidget->mapToGlobal(pos));
}

篇尾

        全局变量是多线程中比较轻量级的共享机制,有很多成熟的消息传递技术,如果你的功能带有业务性,建议多调研选型,比如MQ中间件是典型的消息队列,技术上是典型的生产者<-->消费者的订阅/分发模型,可以减轻很大开发工作。

相关文章:

【QT常用技术讲解】多线程处理+全局变量处理异步事件并获取多个线程返回的结果

前言 QTableView加入勾选项后&#xff08;参考【QT常用技术讲解】QTableView添加QCheckBox、QPushButton&#xff09;&#xff0c;如果支持右键菜单功能&#xff0c;此时就有统一执行多个异步事件&#xff0c;并且统一输出到界面的需求了&#xff0c;本篇结合多线程共享全局变量…...

数组列表中的最大距离

给定 m 个数组&#xff0c;每个数组都已经按照升序排好序了。现在你需要从两个不同的数组中选择两个整数&#xff08;每个数组选一个&#xff09;并且计算它们的距离。两个整数 a 和 b 之间的距离定义为它们差的绝对值 |a-b| 。你的任务就是去找到最大距离 示例 1&#xff1a;…...

C语言新手小白详细教程(7)指针和指针变量

希望文章能够给到初学的你一些启发&#xff5e; 如果觉得文章对你有帮助的话&#xff0c;点赞 关注 收藏支持一下笔者吧&#xff5e; 阅读指南&#xff1a; 开篇说明1、指针的定义接下来我们用图示的形式来解释一下 指针&#xff1a;2、申明指针变量3、取地址符 &4、为指针…...

Kafka保证消息不丢失

Kafka保证消息不丢失 生产者发送消息到Broker丢失 设置异步发送 回调方法中的参数Exception e如果为空 代表发送成功,如果不为空代表发送失败出现异常 消息在Broker中丢失 kafka集群中存在分区机制 分区中分为leader和follower副本 leader负责读写,而follower只负责数据…...

数据结构+基数排序算法

一、问题描述 实现英文单词按字典序排列的基数排序算法 编写一个程序&#xff0c;采用基数排序方法将一组英文单词按字典顺序排 列。假设单词均由小写字母或空格构成&#xff0c;最长的单词有 MaxLen 个 字母&#xff0c;用相关数据进行测试并输出各趟的排序结果。 用例&#…...

C++ list【常用接口、模拟实现等】

1. list的介绍及使用 1.1 list的介绍 1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2.list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前…...

12.面试题——Spring Boot

1.Spring Boot是什么&#xff1f; Spring Boot 是 Spring 开源组织下的子项目&#xff0c;是 Spring 组件一站式解决方案&#xff0c;主要是简化了使用 Spring 的难度&#xff0c;简省了繁重的配置&#xff0c;提供了各种启动器&#xff0c;开发者能快速上手。 2.为什么要用 …...

【前端VUE】npm i 出现版本错误等报错 简单直接解决命令

前端vue npm i 安装时出现 报错原因 在新版本的npm中&#xff0c;默认情况下&#xff0c;npm install遇到冲突的peerDependencies时将失败。 解决办法 使用--force或--legacy-peer-deps可解决这种情况。 --force 会无视冲突&#xff0c;并强制获取远端npm库资源&#xff0…...

精彩回顾 | 风丘科技亮相2024名古屋汽车工程博览会

2024年7月17日-19日&#xff0c;风丘科技联合德国IPETRONIK亮相日本名古屋汽车工程博览会。该展会面向汽车行业不同应用场景&#xff0c;包括新的eAxle、FCEV、ADAS、测试测量系统和ECU测试等相关技术&#xff0c;是一个专为活跃在汽车行业前线的工程师和研究人员举办的汽车技术…...

设计模式21-组合模式

设计模式21-组合模式&#xff08;Composite Pattern&#xff09; 写在前面 动机定义与结构定义结构主要类及其关系 C代码推导优缺点应用场景总结补充叶子节点不重载这三个方法叶子节点重载这三个方法结论 写在前面 数据结构模式 常常有一些组件在内部具有特定的数据结构。如何…...

如何选择深度学习的损失函数和激活函数

一概述 在深度学习中&#xff0c;损失函数&#xff08;Loss Function&#xff09;和激活函数&#xff08;Activation Function&#xff09;是两个至关重要的组件&#xff0c;它们共同影响着模型的训练效果和泛化能力。本文将简要介绍这两个概念&#xff0c;阐述选择它们的重要性…...

DATAX自定义KafkaWriter

因为datax目前不支持写入数据到kafka中&#xff0c;因此本文主要介绍如何基于DataX自定义KafkaWriter&#xff0c;用来同步数据到kafka中。本文偏向实战&#xff0c;datax插件开发理论宝典请参考官方文档&#xff1a; https://github.com/alibaba/DataX/blob/master/dataxPlug…...

Mybatis分页多表多条件查询

个人总结三种方式&#xff1a; Xml、queryWrapper、PageHelper第三方组件这三种方式进行查询&#xff1b; 方式一&#xff1a; xml中联表查询&#xff0c;在mapper中传参IPage<T>和条件Map&#xff08;这里用map装参数&#xff09;。 代码示例&#xff1a; Mapper层 M…...

SpringBoot快速入门(手动创建)

目录 案例&#xff1a;需求 步骤 1 创建Maven项目 2 导入SpringBoot起步依赖 3 定义Controller 4 编写引导类 案例&#xff1a;需求 搭建简单的SpringBoot工程&#xff0c;创建hello的类定义h1的方法&#xff0c;返回Hello SpringBoot! 步骤 1 创建Maven项目 大家&…...

C 408—《数据结构》算法题基础篇—数组(通俗易懂)

目录 Δ前言 一、数组的合并 0.题目&#xff1a; 1.算法设计思想&#xff1a; 2.C语言描述&#xff1a; 3.算法的时间和空间复杂度 : 二、数组元素的倒置 0.题目 : 1.算法设计思想 : 2.C语言描述 : 3.算法的时间和空间复杂度 : 三、数组中特定值元素的删除 0.题目 : …...

AI秘境-墨小黑奇遇记 - 初体验(一)

“怎么可能&#xff01;”墨小黑盯着屏幕上的代码&#xff0c;整个人都不好了。调试了三遍&#xff0c;翻了几遍书&#xff0c;结果还是不对。就像你以为自己早起赶车&#xff0c;结果发现闹钟根本没响一样崩溃。 这是他第一次真正接触人工智能实战任务——实现一个简单的感知…...

文件IO813

标准IO文件定位&#xff1a; fseek函数&#xff1a; 功能&#xff1a;将stream流文件中的文件指针从whence位置开始偏移offset个字节的长度。 int fseek(FILE *stream , long offset, int whence); FILE *stream 指的是所需要定位的文件&#xff08;文化定位前提是文件要被打…...

STP(生成树)的概述和工作原理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…...

从AGV到立库,物流自动化的更迭与未来

AGV叉车 随着柔性制造系统的广泛应用&#xff0c;小批量、多批次的生产需求不断增强&#xff0c;“订单导向”生产已经成为趋势。这也让越来越多的企业认识到&#xff0c;产线的智能设备导入只是第一步&#xff0c;要想达到生产效率的最优解&#xff0c;物流系统的再优化必须提…...

阴阳脚数码管

1.小故事 最近&#xff0c;我接到了一个既“清肺”又“烧脑”的新任务&#xff0c;设计一个低功耗蓝牙肺活量计。在这个项目中我们借鉴了一款蓝牙跳绳的硬件设计方案&#xff0c;特别是它的显示方案——数码管。 在电子工程领域&#xff0c;初学者往往从操作LED开始&#xff…...

Ostrakon-VL-8B在VMware虚拟机中的一站式部署与性能调优

Ostrakon-VL-8B在VMware虚拟机中的一站式部署与性能调优 想在本地隔离环境里跑通一个强大的多模态大模型&#xff0c;比如Ostrakon-VL-8B&#xff0c;但又不想折腾物理机或者担心影响主系统&#xff1f;VMware虚拟机是个不错的选择。不过&#xff0c;在虚拟机里部署AI应用&…...

扩散模型技术演进三部曲:从理论奠基到产业落地的核心突破

1. 扩散模型&#xff1a;一场关于"破坏与重建"的技术革命 想象你正在教一个孩子画画&#xff0c;但用的是一种特别的方式&#xff1a;先给他看一张完整的画作&#xff0c;然后你不断地在上面涂抹修改&#xff0c;直到画作变成一团杂乱无章的线条。接着&#xff0c;你…...

[特殊字符]️ VibeVoice: 开源前沿语音AI,让沟通更高效!

&#x1f399;️ VibeVoice: 开源前沿语音AI VibeVoice是一个开源前沿语音AI模型家族&#xff0c;涵盖文本转语音(TTS)和自动语音识别(ASR)模型。这一项目旨在通过持续的创新&#xff0c;推动语音合成和识别领域的发展。 创新亮点 VibeVoice的核心创新在于采用了持续语音标记…...

从SRCNN到WDSR:图像超分辨率核心演进路径与关键技术剖析

1. 图像超分辨率技术的基础认知 当你用手机拍下一张照片却发现放大后模糊不清时&#xff0c;图像超分辨率技术就能派上用场。这项技术就像给图像装上"显微镜"&#xff0c;能将低分辨率图片转化为清晰的高分辨率版本。不同于简单的插值放大&#xff0c;它通过深度学习…...

Beyond ChatGPT: Building Physical World AI with PaLM-E and VoxPoser (Hands-on Guide)

从语言模型到物理世界操作&#xff1a;PaLM-E与VoxPoser实战指南 当ChatGPT在对话中展现出惊人的语言理解能力时&#xff0c;一个更激动人心的问题浮现&#xff1a;如何让AI系统突破虚拟界限&#xff0c;在物理世界中执行复杂任务&#xff1f;这正是PaLM-E与VoxPoser这类多模态…...

Gitee与奇安信代码卫士的Java安全扫描实战指南

1. 为什么Java项目需要安全扫描&#xff1f; 最近几年&#xff0c;随着数字化转型加速&#xff0c;Java应用的安全问题越来越受到重视。我见过太多因为代码漏洞导致的数据泄露事件&#xff0c;很多都是因为开发过程中忽视了基础的安全检查。就拿去年某知名电商平台的用户信息泄…...

精选 Skills 推荐:10 个让 Coding Agent 如虎添翼的Skills + 优质来源分享

精选 Skills 推荐&#xff1a;10 个让 Coding Agent 如虎添翼的Skills 优质来源分享 本篇是 Vibecoding 系列教程 的工具导向专题篇。 前篇&#xff1a;进阶教程&#xff08;一&#xff09;&#xff1a;MCP Skills 让 coding agent 有自己的工具系列合集&#xff1a;Vibecodi…...

RT thread—iic—at24c04读写操作

at24c04介绍&#xff1a;存储容量&#xff1a;4 Kbits&#xff08;即 512 字节&#xff09;。内部结构为 32 页&#xff0c;每页 16 字节。地址0x000-0x1FF通信接口&#xff1a;标准 I2C&#xff08;时钟线 SCL 和数据线 SDA&#xff09;&#xff0c;支持最高 400 kHz 的快速模…...

新手福音:在快马平台用自然语言生成你的第一个powershell脚本

今天想和大家分享一个特别适合 PowerShell 新手的入门实践。作为一个从零开始学习 PowerShell 的菜鸟&#xff0c;我发现用自然语言描述需求就能生成可运行的脚本&#xff0c;这个体验真的太友好了。 变量定义与数据结构 刚开始学习时&#xff0c;最基础的就是理解变量和数据结…...

Companion Object - 伴生对象 类比java中的什么?

这是一个非常经典且准确的对比问题。简单来说&#xff0c;Kotlin 中的 companion object&#xff08;伴生对象&#xff09;核心类比的是 Java 中的 static&#xff08;静态&#xff09;成员。在 Java 中&#xff0c;如果你想让一个成员&#xff08;方法或变量&#xff09;属于类…...