当前位置: 首页 > 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…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

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

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

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...