Qt 异步编程模式与应用

在现代软件开发中,异步编程已成为提升应用性能和响应性的关键技术。Qt 作为一个强大的跨平台框架,提供了多种异步编程模式,包括信号槽机制、事件循环、线程池、异步 I/O 等。本文将深入探讨 Qt 异步编程的各种模式及其应用场景,帮助开发者构建高效、响应迅速的应用程序。

一、信号槽机制

1. 基本信号槽用法
#include <QObject>
#include <QTimer>
#include <QDebug>class Producer : public QObject {Q_OBJECT
public:explicit Producer(QObject *parent = nullptr) : QObject(parent) {}public slots:void startProducing() {QTimer *timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &Producer::produceData);timer->start(1000);  // 每秒触发一次}signals:void dataReady(int value);private slots:void produceData() {static int counter = 0;emit dataReady(counter++);}
};class Consumer : public QObject {Q_OBJECT
public:explicit Consumer(QObject *parent = nullptr) : QObject(parent) {}public slots:void handleData(int value) {qDebug() << "Received data:" << value;}
};// 使用示例
void useSignalsAndSlots() {Producer producer;Consumer consumer;// 连接信号槽QObject::connect(&producer, &Producer::dataReady, &consumer, &Consumer::handleData);// 启动生产者producer.startProducing();
}
2. 跨线程信号槽
#include <QThread>
#include <QDebug>class Worker : public QObject {Q_OBJECT
public:explicit Worker(QObject *parent = nullptr) : QObject(parent) {}public slots:void doWork() {for (int i = 0; i < 5; ++i) {QThread::sleep(1);emit resultReady(i);}emit finished();}signals:void resultReady(int value);void finished();
};class Controller : public QObject {Q_OBJECT
public:explicit Controller(QObject *parent = nullptr) : QObject(parent) {// 创建工作线程m_thread = new QThread(this);m_worker = new Worker();// 将 worker 移动到新线程m_worker->moveToThread(m_thread);// 连接信号槽connect(m_thread, &QThread::started, m_worker, &Worker::doWork);connect(m_worker, &Worker::resultReady, this, &Controller::handleResults);connect(m_worker, &Worker::finished, m_thread, &QThread::quit);connect(m_worker, &Worker::finished, m_worker, &QObject::deleteLater);connect(m_thread, &QThread::finished, m_thread, &QObject::deleteLater);// 启动线程m_thread->start();}public slots:void handleResults(int value) {qDebug() << "Result received in controller:" << value;}private:QThread *m_thread;Worker *m_worker;
};

二、QtConcurrent 框架

1. 基本用法
#include <QtConcurrent>
#include <QFuture>
#include <QFutureWatcher>
#include <QDebug>// 耗时操作函数
int computeSum(int a, int b) {QThread::sleep(2);  // 模拟耗时操作return a + b;
}// 使用 QtConcurrent::run
void useQtConcurrentRun() {// 在线程池中运行函数QFuture<int> future = QtConcurrent::run(computeSum, 10, 20);// 可以继续执行其他代码...// 等待结果qDebug() << "Result:" << future.result();
}// 使用 QFutureWatcher 监控进度
void useFutureWatcher() {QFutureWatcher<int> *watcher = new QFutureWatcher<int>(this);// 连接信号槽connect(watcher, &QFutureWatcher<int>::finished, this, [watcher]() {qDebug() << "Computation finished. Result:" << watcher->result();watcher->deleteLater();});// 启动任务QFuture<int> future = QtConcurrent::run(computeSum, 50, 60);watcher->setFuture(future);
}
2. 并行处理容器
// 处理函数
void processItem(int &item) {item = item * item;  // 处理每个元素
}// 并行处理容器
void parallelProcessContainer() {QList<int> list = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// 并行处理每个元素QtConcurrent::map(list, processItem);// 或者使用 blockingMap 直接获取结果QList<int> result = QtConcurrent::blockingMapped(list, [](int item) {return item * item;});qDebug() << "Processed list:" << result;
}

三、异步 I/O 操作

1. 异步文件操作
#include <QFile>
#include <QFileDevice>
#include <QDataStream>
#include <QDebug>void asyncFileRead() {QFile file("data.txt");if (!file.open(QIODevice::ReadOnly)) {qDebug() << "Failed to open file";return;}// 使用 QDataStream 进行异步读取QDataStream stream(&file);// 读取文件内容(异步操作)QByteArray data;stream >> data;// 处理读取的数据qDebug() << "Read data size:" << data.size();file.close();
}void asyncFileWrite() {QFile file("output.txt");if (!file.open(QIODevice::WriteOnly)) {qDebug() << "Failed to open file";return;}QDataStream stream(&file);QByteArray data("Hello, World!");// 写入数据(异步操作)stream << data;file.close();
}
2. 异步网络操作
#include <QTcpSocket>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QDebug>// 异步网络请求示例
void asyncNetworkRequest() {QNetworkAccessManager manager;QNetworkRequest request(QUrl("https://api.example.com/data"));// 发送异步请求QNetworkReply *reply = manager.get(request);// 连接响应信号QObject::connect(reply, &QNetworkReply::finished, [reply]() {if (reply->error() == QNetworkReply::NoError) {QByteArray data = reply->readAll();qDebug() << "Received data:" << data;} else {qDebug() << "Error:" << reply->errorString();}reply->deleteLater();});
}// 异步 TCP 通信示例
class AsyncTcpClient : public QObject {Q_OBJECT
public:explicit AsyncTcpClient(QObject *parent = nullptr) : QObject(parent) {m_socket = new QTcpSocket(this);// 连接信号槽connect(m_socket, &QTcpSocket::connected, this, &AsyncTcpClient::connected);connect(m_socket, &QTcpSocket::disconnected, this, &AsyncTcpClient::disconnected);connect(m_socket, &QTcpSocket::readyRead, this, &AsyncTcpClient::readyRead);connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error),this, &AsyncTcpClient::error);}void connectToHost(const QString &host, quint16 port) {m_socket->connectToHost(host, port);}void sendData(const QByteArray &data) {m_socket->write(data);}signals:void dataReceived(const QByteArray &data);private slots:void connected() {qDebug() << "Connected to server";}void disconnected() {qDebug() << "Disconnected from server";}void readyRead() {QByteArray data = m_socket->readAll();emit dataReceived(data);}void error(QAbstractSocket::SocketError socketError) {qDebug() << "Socket error:" << m_socket->errorString();}private:QTcpSocket *m_socket;
};

四、异步任务链与状态机

1. 异步任务链
#include <QStateMachine>
#include <QState>
#include <QFinalState>
#include <QDebug>class AsyncTaskChain : public QObject {Q_OBJECT
public:explicit AsyncTaskChain(QObject *parent = nullptr) : QObject(parent) {// 创建状态机m_machine = new QStateMachine(this);// 创建状态QState *state1 = new QState(m_machine);QState *state2 = new QState(m_machine);QState *state3 = new QState(m_machine);QFinalState *finalState = new QFinalState(m_machine);// 设置状态转换connect(state1, &QState::entered, this, &AsyncTaskChain::task1);connect(state2, &QState::entered, this, &AsyncTaskChain::task2);connect(state3, &QState::entered, this, &AsyncTaskChain::task3);state1->addTransition(this, &AsyncTaskChain::task1Finished, state2);state2->addTransition(this, &AsyncTaskChain::task2Finished, state3);state3->addTransition(this, &AsyncTaskChain::task3Finished, finalState);// 设置初始状态m_machine->setInitialState(state1);// 连接完成信号connect(m_machine, &QStateMachine::finished, this, &AsyncTaskChain::finished);}void start() {m_machine->start();}signals:void task1Finished();void task2Finished();void task3Finished();void finished();private slots:void task1() {qDebug() << "Task 1 started";// 模拟异步操作QTimer::singleShot(1000, this, &AsyncTaskChain::task1Finished);}void task2() {qDebug() << "Task 2 started";// 模拟异步操作QTimer::singleShot(1500, this, &AsyncTaskChain::task2Finished);}void task3() {qDebug() << "Task 3 started";// 模拟异步操作QTimer::singleShot(2000, this, &AsyncTaskChain::task3Finished);}private:QStateMachine *m_machine;
};
2. 使用 QPromise 和 QFuture
#include <QFuture>
#include <QFutureWatcher>
#include <QPromise>
#include <QtConcurrent>
#include <QDebug>// 异步任务函数
QFuture<QString> asyncTask(const QString &input) {return QtConcurrent::run([input]() {QThread::sleep(2);  // 模拟耗时操作return "Processed: " + input;});
}// 链式调用异步任务
void chainAsyncTasks() {// 第一个任务QFuture<QString> future1 = asyncTask("Task 1");// 创建监听器QFutureWatcher<QString> *watcher1 = new QFutureWatcher<QString>(this);watcher1->setFuture(future1);// 连接完成信号connect(watcher1, &QFutureWatcher<QString>::finished, this, [this, watcher1]() {QString result1 = watcher1->result();qDebug() << "Result 1:" << result1;watcher1->deleteLater();// 启动第二个任务QFuture<QString> future2 = asyncTask(result1);// 创建第二个监听器QFutureWatcher<QString> *watcher2 = new QFutureWatcher<QString>(this);watcher2->setFuture(future2);// 连接第二个任务的完成信号connect(watcher2, &QFutureWatcher<QString>::finished, this, [watcher2]() {QString result2 = watcher2->result();qDebug() << "Result 2:" << result2;watcher2->deleteLater();});});
}

五、异步 UI 更新

1. 安全的 UI 更新方法
#include <QMainWindow>
#include <QPushButton>
#include <QThread>
#include <QDebug>class MainWindow : public QMainWindow {Q_OBJECT
public:explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {m_button = new QPushButton("Start", this);setCentralWidget(m_button);connect(m_button, &QPushButton::clicked, this, &MainWindow::startTask);}private slots:void startTask() {// 创建工作线程QThread *thread = new QThread(this);// 创建工作者class Worker : public QObject {Q_OBJECTpublic:explicit Worker(QObject *parent = nullptr) : QObject(parent) {}signals:void progressUpdated(int value);public slots:void doWork() {for (int i = 0; i <= 100; ++i) {QThread::msleep(50);emit progressUpdated(i);}emit finished();}void finished() {thread()->quit();thread()->deleteLater();deleteLater();}};Worker *worker = new Worker();worker->moveToThread(thread);// 连接信号槽connect(thread, &QThread::started, worker, &Worker::doWork);connect(worker, &Worker::progressUpdated, this, &MainWindow::updateProgress);connect(worker, &Worker::finished, worker, &QObject::deleteLater);connect(thread, &QThread::finished, thread, &QObject::deleteLater);// 启动线程thread->start();}void updateProgress(int value) {m_button->setText(QString("Progress: %1%").arg(value));}private:QPushButton *m_button;
};
2. 使用 Qt 的 invokeMethod
// 线程安全的 UI 更新
void updateUI(const QString &text) {// 使用 Qt::QueuedConnection 确保在主线程执行QMetaObject::invokeMethod(ui->label, "setText", Qt::QueuedConnection, Q_ARG(QString, text));
}// 在线程中调用
void Worker::run() {// 执行一些操作...// 更新 UIupdateUI("Operation completed");
}

六、异步编程最佳实践

1. 避免阻塞事件循环
// 不良实践:阻塞事件循环
void badPractice() {// 执行耗时操作,会阻塞 UIQThread::sleep(5);// 更新 UI,此时 UI 已冻结 5 秒ui->label->setText("Done");
}// 良好实践:使用异步方式
void goodPractice() {// 在另一个线程执行耗时操作QtConcurrent::run([this]() {// 执行耗时操作QThread::sleep(5);// 更新 UI(在主线程执行)QMetaObject::invokeMethod(this, [this]() {ui->label->setText("Done");}, Qt::QueuedConnection);});
}
2. 合理管理异步资源
// 使用智能指针管理资源
void manageResources() {// 创建共享资源QSharedPointer<Resource> resource(new Resource());// 在异步任务中使用资源QtConcurrent::run([resource]() {// 使用资源resource->doSomething();});// 主线程可以继续执行其他操作,资源会在所有引用消失后自动释放
}

七、总结

Qt 提供了丰富的异步编程模式,能够满足不同场景下的需求。合理使用这些模式可以显著提升应用的性能和响应性。本文介绍了 Qt 中主要的异步编程模式及其应用:

  1. 信号槽机制:Qt 核心的异步通信机制,线程安全且使用简单
  2. QtConcurrent 框架:提供高级接口,简化并行任务的实现
  3. 异步 I/O 操作:包括文件、网络等 I/O 操作的异步实现
  4. 异步任务链与状态机:用于组织复杂的异步工作流程
  5. 异步 UI 更新:安全更新 UI 的方法,避免界面冻结

在实际开发中,应根据具体场景选择合适的异步模式,并遵循以下最佳实践:

  • 避免阻塞事件循环,保持 UI 响应性
  • 合理管理异步资源,避免内存泄漏
  • 使用信号槽或 QMetaObject::invokeMethod 进行线程间通信
  • 考虑使用状态机管理复杂的异步工作流程
  • 使用智能指针管理异步任务中的资源

通过这些技术和实践,可以构建高效、稳定、响应迅速的 Qt 应用程序。

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

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

相关文章

面试150 数字范围按位与

思路 只要 left < right&#xff0c;说明两者在某些低位上存在不同&#xff0c;为了找到它们的公共前缀&#xff08;高位相同部分&#xff09;&#xff0c;不断将 left 和 right 同时右移&#xff08;即除以2&#xff09;&#xff0c;直到它们相等&#xff0c;记录右移的次数…

数据库HB OB mysql ck startrocks, ES存储特点,以及应用场景

这些数据库和存储引擎主要有:HB(HBase)、OB(OceanBase)、MySQL、ClickHouse(CK)、StarRocks、Elasticsearch(ES),下面分别介绍它们的存储特点以及典型应用场景。 1. HBase (HB) 存储特点 分布式、面向列的NoSQL数据库 采用HDFS存储,数据以表、row key、列族、时间戳…

Java技术栈/面试题合集(17)-Git篇

场景 Java入门、进阶、强化、扩展、知识体系完善等知识点学习、性能优化、源码分析专栏分享: Java入门、进阶、强化、扩展、知识体系完善等知识点学习、性能优化、源码分析专栏分享_java高级进阶-CSDN博客 通过对面试题进行系统的复习可以对Java体系的知识点进行查漏补缺。…

破局与重构:King’s LIMS 引领电子行业实验室智能化转型

在全球化高新技术竞争白热化背景下&#xff0c;电子行业正经历从规模导向扩张向质量效益跃升的战略转型。终端用户对产品性能的极致化追求、行业质量合规标准的持续迭代升级&#xff0c;以及检测数据的指数级增长&#xff0c;共同形成"需求牵引供给、供给创造需求"的…

暑期算法训练.9

目录 43 .力扣75 颜色分类 43.1 题目解析&#xff1a; 43.2 算法思路&#xff1a; 43.3 代码演示&#xff1a; 43.4 总结反思&#xff1a; 44. 力扣 912 排序数组 44.1 题目解析&#xff1a; 44.2 算法思路&#xff1a; 44.3 代码演示&#xff1a; ​编辑 44.4 总结反…

2.安装CUDA详细步骤(含安装截图)

2.安装CUDA 第一步&#xff1a;安装anaconda 注意&#xff1a;安装CUDA之前需要安装好anaconda&#xff0c;详见安装anaconda详细步骤&#xff08;含安装截图&#xff09; 文章目录2.安装CUDA2.0 CUDA是什么&#xff0c;为什么要安装它&#xff1f;2.1 验证计算机是否安装CUDA2…

Triton IR

Triton IR语法 Triton IR的语句遵从MLIR Dialect的语法定义规范&#xff0c;示例如下&#xff1a; %3 tt.splat %1 : i32 -> tensor<1024xi32> loc(#loc5) 其中&#xff1a; %0&#xff1a;右边expression的结果值的名字&#xff08;Value的name&#xff09; tt…

掌握JavaScript函数封装与作用域

JavaScript 基础 - 第4天笔记理解封装的意义&#xff0c;能够通过函数的声明实现逻辑的封装&#xff0c;知道对象数据类型的特征&#xff0c;结合数学对象实现简单计算功能。理解函数的封装的特征掌握函数声明的语法理解什么是函数的返回值知道并能使用常见的内置函数函数理解函…

Datawhale AI 夏令营—科大讯飞AI大赛(大模型技术)—让大模型理解表格数据(列车信息表)

目录 一、本次赛事目标&#xff1a;让大模型理解表格数据&#xff08;列车信息表&#xff09; 二、分析赛题、对问题进行建模 赛事背景 赛题解读 数据分析与探索 赛题要点与难点 解题思考过程 三、Baseline方案 Baseline概况 Baseline运行步骤 Baseline文件概况 Ba…

SSH连接失败排查与解决教程: Connection refused

前言 当使用云服务器&#xff08;如阿里云、腾讯云、AWS 等&#xff09;时&#xff0c;尝试在本地PC端使用图形化工具如 FinalShell、XShell可能会遇到 SSH 连接失败的问题。本文列举 SSH 连接失败的常见原因&#xff0c;并提供对应解决方案&#xff0c;帮助快速定位并解决问题…

性能优化:Vue 3 `v-memo` 指令详解

v-memo 是 Vue 3 提供的一个性能优化工具&#xff0c;能帮助开发者缓存模板内容&#xff0c;减少不必要的渲染开销。本文将介绍 v-memo 的引入版本、作用、使用方法和实现原理&#xff0c;并通过示例说明如何使用它。内容基于 Vue 3.5.18&#xff08;截至 2025 年 7 月的最新版…

标准库开发和寄存器开发的区别

1.标准库void GPIO_Toggle_INIT(void)//初始化GPIO {GPIO_InitTypeDef GPIO_InitStructure {0};//定义GPIO结构体RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//使能GPIO时钟GPIO_InitStructure.GPIO_Pin GPIO_Pin_2;//GPIO引脚选择GPIO_InitStructure.GPIO_Mode …

在 WebSocket 中使用 @Autowired 时遇到空指针异常

背景&#xff1a;在websocket在有新的连接加入进来时&#xff0c;调用servier中的服务&#xff0c;使用 Autowired 注入的 Bean 竟然是 null&#xff01;这并非 Spring 的 Bug&#xff0c;而是对 WebSocket 生命周期管理理解不足导致的。了解这个问题&#xff0c;我们需要区分两…

MGER实验

一、实验拓扑图二、配置1.R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有IP地址R1侧为15.1.1.1&#xff0c;对应R5为15.1.1.2R2侧为25.1.1.2&#xff0c;对应R5为25.1.1.1R3侧为35.1.1.2&#xff0c;对应R5为35.1.1.1R4侧为45.1.1.2&#xff0c;对应R…

基于 XGBoost 与 SHAP 的医疗自动化办公与可视化系统(下)

— 登录接口 — @app.post(“/token”) def login(form_data: OAuth2PasswordRequestForm = Depends()): user = fake_users_db.get(form_data.username) if not user or form_data.password != user[“password”]: raise HTTPException(status_code=400, detail=“用户名或密…

python学智能算法(二十九)|SVM-拉格朗日函数求解中-KKT条件

引言 前序学习进程中&#xff0c;对拉格朗日函数执行了初步求导&#xff0c;并获得了简化后的拉格朗日函数极值计算式&#xff1a; L(w,b,α)∑i1mαi−12∑i,j1mαiαjyiyjxiTxjL(w,b,\alpha)\sum_{i1}^{m}\alpha_{i}-\frac{1}{2}\sum_{i,j1}^{m}\alpha_{i}\alpha_{j}y_{i}y_…

【AI论文】MiroMind-M1:通过情境感知多阶段策略优化实现数学推理的开源新进展

摘要&#xff1a;近期&#xff0c;大型语言模型已从流畅的文本生成发展至能在多个领域进行高级推理&#xff0c;由此催生了推理语言模型&#xff08;RLMs&#xff09;。在众多领域中&#xff0c;数学推理堪称代表性基准&#xff0c;因为它需要精确的多步骤逻辑与抽象推理能力&a…

《使用Qt Quick从零构建AI螺丝瑕疵检测系统》——6. 传统算法实战:用OpenCV测量螺丝尺寸

目录一、概述1.1 背景介绍&#xff1a;从“看见”到“看懂”1.2 学习目标二、图像预处理&#xff1a;让目标更突出三、轮廓发现与尺寸测量四、总结与展望一、概述 1.1 背景介绍&#xff1a;从“看见”到“看懂” 在上一篇文章中&#xff0c;我们成功地为应用程序安装了“眼睛…

《人性的弱点》重构【01】

手上有本《人性的弱点》&#xff08;韩文桥 译&#xff0c;浙江文艺出版社&#xff0c;2017.1出版&#xff09;&#xff0c;前些年买的&#xff0c;近期翻出来看看。这门书虽成书于80多年前&#xff0c;但卡耐基对人性洞察之深刻&#xff0c;时至今日&#xff0c;并未觉得过时。…

k8s开启审计日志

k8s默认是关闭审计功能的&#xff0c;想看的话需要到apiserver的pod中才可以。 开启此功能是为了进行k8s审计日志的收集&#xff0c;方便我们查看k8s中用户的各自操作。 开启此功能之前&#xff0c;我们要先创建个审计策略文件audit-policy.yaml 例如以下的测验文件 apiVersion…