Qt线程高级应用

一般我们在用Qt开发时,把耗时操作放在线程中执行,避免卡界面,Qt的线程使用有两种方式,一种是继承QThread,一种是moveToThread的方式,以及QtConcurrent方式
首先我们来看第一种:

#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H#include <QDebug>
#include <QThread>
#include <QDateTime>#define PRINTTIME QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");class WorkerThread : public QThread
{Q_OBJECT
public:explicit WorkerThread(QObject *parent = nullptr);int getThreadFun();void run() override{QString result = QString("WorkerThread");/* ... here is the expensive or blocking operation ... */QThread::sleep(3);qDebug() << "WorkerThread::run===============currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;emit resultReady(result);}signals:void resultReady(const QString &result);};
#endif // WORKERTHREAD_H

#include "workerthread.h"WorkerThread::WorkerThread(QObject *parent) : QThread(parent)
{}int WorkerThread::getThreadFun()
{qDebug() << "Dialog::getThreadFun============currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;int id = (int)QThread::currentThreadId();QThread::sleep(2);return id;}

 使用线程:

void Dialog::initData()
{m_workerThread = new WorkerThread(this);connect(m_workerThread, &WorkerThread::resultReady, this, &Dialog::handleResults1);//connect(m_workerThread, &WorkerThread::finished, m_workerThread, &Dialog::deleteLater);//m_workerThread->start();connect(ui->btn1, SIGNAL(clicked()), this, SLOT(slotBtn1()));
}void Dialog::slotBtn1()
{qDebug() << "Dialog::slotBtn1================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;m_workerThread->start();qDebug() << "Dialog::slotBtn1================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;m_workerThread->getThreadFun();
}

运行结果:

 从以上信息可以看到,只有run函数里的执行是属于子线程,getThreadFun函数虽然是WorkerThread类的,但执行起来并不属于子线程,它的线程号与主线程一样,同时,开启线程后还没等结果就执行下面的语句了。run函数执行完,线程就结束了。

那么有没有一种情况,线程一直处理运行中呢?下面看第2种线程的方式:

#ifndef WORKER_H
#define WORKER_H#include <QObject>
#include <QDebug>
#include <QThread>
#include <QDateTime>#define PRINTTIME QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");class Worker : public QObject
{Q_OBJECT
public:explicit Worker(QObject *parent = nullptr);int getThreadFun();public slots:void doWork(const QString &parameter){QString result = QString("currentThreadId==%1").arg((int)QThread::currentThreadId());/* ... here is the expensive or blocking operation ... */QThread::sleep(3);qDebug() << "Worker::doWork==================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;emit resultReady(result);}signals:void resultReady(const QString &result);
};#endif // WORKER_H
#include "worker.h"Worker::Worker(QObject *parent): QObject{parent}
{}int Worker::getThreadFun()
{qDebug() << "Worker::getThreadFun============currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;int id = (int)QThread::currentThreadId();QThread::sleep(2);return id;}

使用线程:

void Dialog::initData()
{m_worker = new Worker;m_worker->moveToThread(&workerThread);connect(&workerThread, &QThread::finished, m_worker, &QObject::deleteLater);connect(this, &Dialog::operate, m_worker, &Worker::doWork);connect(m_worker, &Worker::resultReady, this, &Dialog::handleResults2);workerThread.start();connect(ui->btn2, SIGNAL(clicked()), this, SLOT(slotBtn2()));
}void Dialog::slotBtn2()
{qDebug() << "Dialog::slotBtn2=======1========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;emit operate("Worker");qDebug() << "Dialog::slotBtn2=======2========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;m_worker->getThreadFun();
}void Dialog::handleResults2()
{qDebug() << "Dialog::handleResults2==========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
}

运行结果:

 从上面结果也可以看出,由operate信号触发的槽函数是子线程,直接调用getThreadFun函数还是属于子线程,但这个与第一种线程的方案不同在于,线程一起处理运行中,只要触发operate信号都会执行槽函数的子线程,以上两种情况都是线程还没执行完,调用线程的函数就已经结束了。

但有时候我们需要函数的结果,并且根据结果执行不同的分支要求,那边没有一种方案可以这种做呢,下面看第3种线程方式,使用QtConcurrent获取线程执行的返回结果:

#include "dialog.h"
#include "ui_dialog.h"
#include "workerthread.h"
#include "worker.h"
#include <QDebug>
#include <QSerialPort>
#include <QtConcurrent>
#include <QTime>
#include <QDebug>
#include <QEventLoop>
#include <QtConcurrentMap>
#include <QSerialPortInfo>using namespace QtConcurrent;#define PRINTTIME QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog)
{ui->setupUi(this);initData();}Dialog::~Dialog()
{workerThread.quit();workerThread.wait();m_workerThread->quit();m_workerThread->wait();delete ui;
}void Dialog::initData()
{connect(ui->btn3, SIGNAL(clicked()), this, SLOT(slotBtn3()));
}int threadFun3(int a1, int a2)
{qDebug() << "threadFun3======================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;QThread::sleep(2);qDebug() << "threadFun3======================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;return a1 + a2;
}void Dialog::slotBtn3()
{int a1 = 5092;int a2 = 542451;qDebug() << "Dialog::slotBtn3=======1========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;QFuture<int> future =QtConcurrent::run(threadFun3, a1, a2);int result = future.result();qDebug() << "Dialog::slotBtn3=======2========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;qDebug() << "Dialog::slotBtn3================result================" << result << PRINTTIME;
}

运行结果:

这种方案可以获取线程执行返回的结果了,但是这也存在一个问题,这个返回结果是待slotBtn3函数调用完了才返回,有时我们需要我等待这个结果再执行下面的代码。这时候就需要采用另外一种 方式下了。直接上代码:

void Dialog::initData()
{connect(ui->btn4, SIGNAL(clicked()), this, SLOT(slotBtn4()));
}//这里检测串口连接设备,连上设备才算打开串口成功
QString checkDeviceConnectPort()
{QString openName = "";QString tempData{""};QThread::sleep(2);qDebug() << "checkDeviceConnectPort======================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;QSerialPort *serialPort = new QSerialPort();foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){serialPort->setPort(info);if(info.portName().contains("Bluetooth", Qt::CaseInsensitive))continue;bool isOpen = serialPort->open(QIODevice::ReadWrite);qDebug() << "checkDeviceConnectPort(================isOpen==" << isOpen << info.portName() << PRINTTIME;if(isOpen){//设置参数serialPort->setBaudRate(115200);                          //波特率115200serialPort->setDataBits(QSerialPort::Data8);              //数据位8serialPort->setStopBits(QSerialPort::OneStop);            //停止位1serialPort->setParity(QSerialPort::NoParity);             //校验位 无serialPort->setFlowControl(QSerialPort::NoFlowControl);   //设置为无流控制serialPort->setReadBufferSize(40960);                     //最大缓存40960QByteArray sendData("XX\n");//sendData的数据// 写入发送缓存区qint64 sendDataLen = serialPort->write(sendData);qDebug() << "checkDeviceConnectPort================sendDataLen=====" << sendDataLen;qApp->processEvents();qDebug() << "SerialPortManage::checkDeviceConnectPort=================processEvents================" << PRINTTIME;while(serialPort->isOpen() && serialPort->waitForReadyRead(3000)) {QString array = serialPort->readAll();qDebug() << "SerialPortManage::checkDeviceConnectPort=====================array============" << array << PRINTTIME;tempData.append(array);if(array.isEmpty()) {qApp->processEvents();}if(tempData.contains("end")){qDebug() << "checkDeviceConnectPort=================tempData================" << tempData;break;}}if(openName.size() > 0){break;}}} //end foreach(qDebug() << "checkDeviceConnectPort=================openName=================" << openName << PRINTTIME;serialPort->close();serialPort->deleteLater();return openName;
}void Dialog::slotBtn4()
{qDebug() << "Dialog::slotBtn4===1========================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;QFuture<QString> future = QtConcurrent::run(checkDeviceConnectPort);while (!future.isFinished()) {QApplication::processEvents(QEventLoop::AllEvents, 30);}qDebug() << "Dialog::slotBtn4============================result==============" << future.result() << PRINTTIME;qDebug() << "Dialog::slotBtn4===2========================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;}

运行结果:

从上面可以看到,待线程函数执行完了,才会执行

qDebug() << "Dialog::slotBtn4============================result==============" << future.result() << PRINTTIME;
    qDebug() << "Dialog::slotBtn4===2========================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;

的代码,这样就可以根据结果处理后续的逻辑了,同时也不会卡界面。

完整代码中下:

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QThread>QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACEclass WorkerThread;
class Worker;class Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = nullptr);~Dialog();void initData();public slots:void slotBtn1();void slotBtn2();void slotBtn3();void slotBtn4();void handleResults1();void handleResults2();signals:void operate(const QString &result);private:Ui::Dialog *ui;WorkerThread *m_workerThread{nullptr};QThread workerThread;Worker *m_worker{nullptr};
};
#endif // DIALOG_H

dialog.cpp文件

#include "dialog.h"
#include "ui_dialog.h"
#include "workerthread.h"
#include "worker.h"
#include <QDebug>
#include <QSerialPort>
#include <QtConcurrent>
#include <QTime>
#include <QDebug>
#include <QEventLoop>
#include <QtConcurrentMap>
#include <QSerialPortInfo>using namespace QtConcurrent;#define PRINTTIME QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog)
{ui->setupUi(this);initData();}Dialog::~Dialog()
{workerThread.quit();workerThread.wait();m_workerThread->quit();m_workerThread->wait();delete ui;
}void Dialog::initData()
{m_workerThread = new WorkerThread(this);connect(m_workerThread, &WorkerThread::resultReady, this, &Dialog::handleResults1);//connect(m_workerThread, &WorkerThread::finished, m_workerThread, &Dialog::deleteLater);//m_workerThread->start();m_worker = new Worker;m_worker->moveToThread(&workerThread);connect(&workerThread, &QThread::finished, m_worker, &QObject::deleteLater);connect(this, &Dialog::operate, m_worker, &Worker::doWork);connect(m_worker, &Worker::resultReady, this, &Dialog::handleResults2);workerThread.start();connect(ui->btn1, SIGNAL(clicked()), this, SLOT(slotBtn1()));connect(ui->btn2, SIGNAL(clicked()), this, SLOT(slotBtn2()));connect(ui->btn3, SIGNAL(clicked()), this, SLOT(slotBtn3()));connect(ui->btn4, SIGNAL(clicked()), this, SLOT(slotBtn4()));
}void Dialog::slotBtn1()
{qDebug() << "Dialog::slotBtn1================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;m_workerThread->start();qDebug() << "Dialog::slotBtn1================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;m_workerThread->getThreadFun();
}void Dialog::slotBtn2()
{qDebug() << "Dialog::slotBtn2=======1========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;emit operate("Worker");qDebug() << "Dialog::slotBtn2=======2========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;m_worker->getThreadFun();
}int threadFun3(int a1, int a2)
{qDebug() << "threadFun3======================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;QThread::sleep(2);qDebug() << "threadFun3======================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;return a1 + a2;
}void Dialog::slotBtn3()
{int a1 = 5092;int a2 = 542451;QString str = "AAAAAAAAAAAA";qDebug() << "Dialog::slotBtn3=======1========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;QFuture<int> future =QtConcurrent::run(threadFun3, a1, a2);int result = future.result();qDebug() << "Dialog::slotBtn3=======2========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;qDebug() << "Dialog::slotBtn3================result================" << result << PRINTTIME;
}//这里检测串口连接设备,连上设备才算打开串口成功
QString checkDeviceConnectPort()
{QString openName = "";QString tempData{""};QThread::sleep(2);qDebug() << "checkDeviceConnectPort======================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;QSerialPort *serialPort = new QSerialPort();foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){serialPort->setPort(info);if(info.portName().contains("Bluetooth", Qt::CaseInsensitive))continue;bool isOpen = serialPort->open(QIODevice::ReadWrite);qDebug() << "checkDeviceConnectPort(================isOpen==" << isOpen << info.portName() << PRINTTIME;if(isOpen){//设置参数serialPort->setBaudRate(115200);                          //波特率115200serialPort->setDataBits(QSerialPort::Data8);              //数据位8serialPort->setStopBits(QSerialPort::OneStop);            //停止位1serialPort->setParity(QSerialPort::NoParity);             //校验位 无serialPort->setFlowControl(QSerialPort::NoFlowControl);   //设置为无流控制serialPort->setReadBufferSize(40960);                     //最大缓存40960QByteArray sendData("XX\n");//sendData的数据// 写入发送缓存区qint64 sendDataLen = serialPort->write(sendData);qDebug() << "checkDeviceConnectPort================sendDataLen=====" << sendDataLen;qApp->processEvents();qDebug() << "SerialPortManage::checkDeviceConnectPort=================processEvents================" << PRINTTIME;while(serialPort->isOpen() && serialPort->waitForReadyRead(3000)) {QString array = serialPort->readAll();qDebug() << "SerialPortManage::checkDeviceConnectPort=====================array============" << array << PRINTTIME;tempData.append(array);if(array.isEmpty()) {qApp->processEvents();}if(tempData.contains("end")){qDebug() << "checkDeviceConnectPort=================tempData================" << tempData;break;}}if(openName.size() > 0){break;}}} //end foreach(qDebug() << "checkDeviceConnectPort=================openName=================" << openName << PRINTTIME;serialPort->close();serialPort->deleteLater();return openName;
}void Dialog::slotBtn4()
{qDebug() << "Dialog::slotBtn4===1========================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;QFuture<QString> future = QtConcurrent::run(checkDeviceConnectPort);while (!future.isFinished()) {QApplication::processEvents(QEventLoop::AllEvents, 30);}qDebug() << "Dialog::slotBtn4============================result==============" << future.result() << PRINTTIME;qDebug() << "Dialog::slotBtn4===2========================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;}void Dialog::handleResults1()
{qDebug() << "Dialog::handleResults1==========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
}void Dialog::handleResults2()
{qDebug() << "Dialog::handleResults2==========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
}
QT       += core gui serialport concurrentgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++17# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \dialog.cpp \worker.cpp \workerthread.cppHEADERS += \dialog.h \worker.h \workerthread.hFORMS += \dialog.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

UI布局:

参考:

QFutureWatcher获取QtConcurrent::run线程函数的返回值_qt怎样异步获取qtconcurrent::run创建的线程的返回结果-CSDN博客

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

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

相关文章

上推加载更多组件

本组件使用的是TaroReact 实现的 &#xff0c;具体代码如下 一共分为tsx和less文件 //index.tsx /** RefreshLoading* description 上推加载更多组件* param loading boolean* param style* returns*/import { View } from "tarojs/components"; import React, { FC…

DELL R740 两个raid10安装centos7.9

DELL R740 两个raid10安装centos7.9 服务器硬件配置&#xff1a; DELL R740&#xff1a;R740/4214R (12C,100W,2.4GHz)*2/128G(32G DDR4 RDIMM)*4 /600G SAS 10K *41.2T SAS 转速10K*4/H750 &#xff08;8G 缓存&#xff09;/750W *2/iDRAC9 要求&#xff1a;600G*4&#xf…

HTML5+CSS3小实例:创意修剪路径图像悬停效果

实例:创意修剪路径图像悬停效果 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge&qu…

安卓手机日程不响铃或弹窗提醒怎么设置?

在庞大的安卓手机用户群体中&#xff0c;诸多手机品牌如小米、OPPO、vivo、荣耀等都为用户提供了丰富的功能和便捷的体验。然而&#xff0c;有时候我们在手机日历中设置了提醒时间&#xff0c;却发现安卓手机的日程提醒并没有如期响铃或弹窗&#xff0c;这着实令人头疼。那么安…

内网安全:Exchange服务

目录 Exchange服务 实验环境 域横向移动-内网服务-Exchange探针 一. 端口扫描 二. SPN扫描 三. 脚本探针(还可以探针是否有安全漏洞) 域横向移动-内网服务-Exchange爆破 一 .BurpSuite Intruder模块爆破 域横向移动-内网服务-Exchange漏洞 CVE-2020-17144 Exchange R…

再学http

HTTP状态码 1xx 信息性状态码 websocket upgrade 2xx 成功状态码 200 服务器已成功处理了请求204(没有响应体)206(范围请求 暂停继续下载) 3xx 重定向状态码 301(永久) &#xff1a;请求的页面已永久跳转到新的url302(临时) &#xff1a;允许各种各样的重定向&#xff0c;一般…

[go语言]用map类型写一个简单的登陆注册系统

目录 1、题目概述 2、知识点与代码概述 3、代码总结 1、题目概述 每个注册用户的名字都是唯一的&#xff0c;要存储的内容包括&#xff1a;姓名、性别、登陆密码、年龄等信息&#xff0c;系统有注册和登录两个选项&#xff1a;注册时要验证用户是否注册过了&#xff0c;登录…

路由懒加载(React和Vue)

1、为了提升性能&#xff0c;将懒加载的文件单独打包 在webpack.config.js配置打包成chunks // 打包到不同的chunks optimization: {// 将动态加载(懒加载)的文件(imort())单独打包splitChunks: {chunks: "all",},// 避免分割缓存失效runtimeChunk: {name: (entrypo…

[机器学习]简单线性回归——最小二乘法

一.线性回归及最小二乘法概念 2.代码实现 # 0.引入依赖 import numpy as np import matplotlib.pyplot as plt# 1.导入数据 points np.genfromtxt(data.csv, delimiter,) # points[0,0]# 提取points中的两列数据&#xff0c;分别作为x&#xff0c;y x points[:, 0] y poi…

Spring Cloud + Vue前后端分离-第14章 项目优化

源代码在GitHub - 629y/course: Spring Cloud Vue前后端分离-在线课程 Spring Cloud Vue前后端分离-第14章 项目优化 14-1 项目初始化 1.增加readme.md&#xff0c;添加项目介绍 2.修改初始化sql README.md readme.md是用来写一些项目描述信息&#xff0c;git远程仓库可…

Python基础篇: python安装

Python的安装 一、了解python二、官网找到下载链接三、安装3.1、选择自定义安装&#xff0c;并且选择添加系统变量3.2、选择软件安装位置&#xff0c;尽量安装在C盘之外的盘内&#xff0c;并且安装路径不要有中文3.3、等待进度条的完成&#xff0c;该过程会比较慢&#xff0c;请…

【数据分析】numpy基础第二天

文章目录 前言数组的形状变换reshape的基本介绍使用reshapereshape([10, 1])运行结果reshape自动判断形状reshape([-1, 1])运行结果 合并数组使用vstack和hstackvstack和hstack的运行结果使用concatenateconcatenate运行结果 分割数组array_split运行结果 数组的条件筛选条件筛…