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

QT中多线程的实现

采用官方推荐的 QObject::moveToThread 方式实现(相比继承 QThread 更灵活),包含耗时任务执行、主线程通信、线程安全退出等核心功能。

环境说明

  • Qt 版本:Qt 5.15+ 或 Qt 6(兼容)
  • 项目类型:GUI 程序(含界面显示线程状态和结果)
  • 依赖模块:需在 .pro 文件中添加 QT += core gui widgets

完整代码(含注释)

1. 项目文件(.pro)
QT       += core gui widgets
CONFIG   += c++11TARGET = QtMultiThreadDemo
TEMPLATE = appSOURCES += main.cpp \mainwindow.cppHEADERS += \mainwindow.h \worker.hFORMS += mainwindow.ui
2. 工作类(worker.h)
#ifndef WORKER_H
#define WORKER_H#include <QObject>
#include <QThread>
#include <QDebug>// 工作类:负责执行耗时任务(如数据计算、文件读写等)
class Worker : public QObject {Q_OBJECT
public:explicit Worker(QObject *parent = nullptr) : QObject(parent) {}signals:// 发送任务进度(参数:当前进度,总进度)void progressUpdated(int current, int total);// 发送任务结果(参数:结果字符串)void resultReady(const QString &result);public slots:// 启动任务的槽函数(将在子线程中执行)void startTask() {const int totalSteps = 10;for (int i = 0; i <= totalSteps; ++i) {// 模拟耗时操作(如计算、延迟)QThread::msleep(500); // 暂停 500ms// 发送进度(跨线程信号,自动排队到主线程)emit progressUpdated(i, totalSteps);}// 发送最终结果emit resultReady("任务完成!总耗时:5秒");}
};
3. 主窗口类(mainwindow.h)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QThread>
#include "worker.h"QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:// 点击按钮启动任务void on_startBtn_clicked();// 接收进度更新的槽函数(主线程执行)void onProgressUpdated(int current, int total);// 接收任务结果的槽函数(主线程执行)void onResultReady(const QString &result);private:Ui::MainWindow *ui;QThread *workerThread; // 子线程对象Worker *worker;        // 工作类实例
};
#endif
4. 主窗口实现(mainwindow.cpp)
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);setWindowTitle("Qt 多线程示例");// 初始化子线程和工作类workerThread = new QThread(this); // 父对象设为窗口,自动管理生命周期worker = new Worker();            // 工作类无父对象(后续移动到子线程)// 将工作类移动到子线程worker->moveToThread(workerThread);// 连接信号槽(跨线程自动队列)connect(ui->startBtn, &QPushButton::clicked, this, &MainWindow::on_startBtn_clicked);connect(worker, &Worker::progressUpdated, this, &MainWindow::onProgressUpdated);connect(worker, &Worker::resultReady, this, &MainWindow::onResultReady);// 子线程结束时释放工作类(可选)connect(workerThread, &QThread::finished, worker, &QObject::deleteLater);
}MainWindow::~MainWindow() {// 窗口关闭时,停止子线程并等待退出workerThread->quit();workerThread->wait(); // 等待线程结束(避免强制终止导致资源泄漏)delete ui;
}// 点击按钮启动任务
void MainWindow::on_startBtn_clicked() {if (!workerThread->isRunning()) {// 启动子线程(不直接执行任务,而是触发工作类的槽函数)workerThread->start();// 调用工作类的 startTask 槽函数(在子线程中执行)QMetaObject::invokeMethod(worker, "startTask", Qt::QueuedConnection);ui->startBtn->setEnabled(false); // 防止重复点击}
}// 更新进度(主线程执行)
void MainWindow::onProgressUpdated(int current, int total) {ui->progressBar->setRange(0, total);ui->progressBar->setValue(current);ui->statusLabel->setText(QString("进度:%1/%2").arg(current).arg(total));
}// 接收任务结果(主线程执行)
void MainWindow::onResultReady(const QString &result) {ui->statusLabel->setText(result);ui->startBtn->setEnabled(true); // 允许再次启动workerThread->quit(); // 任务完成后停止子线程(可选)
}
5. 主函数(main.cpp)
#include "mainwindow.h"
#include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}
6. 界面文件(mainwindow.ui)

通过 Qt Designer 设计界面,包含以下控件(可直接复制 XML 到 .ui 文件):

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>MainWindow</class><widget class="QMainWindow" name="MainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>400</width><height>200</height></rect></property><property name="windowTitle"><string>Qt 多线程示例</string></property><widget class="QWidget" name="centralwidget"><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QProgressBar" name="progressBar"><property name="value"><number>0</number></property></widget></item><item><widget class="QLabel" name="statusLabel"><property name="text"><string>点击按钮启动任务</string></property></widget></item><item><widget class="QPushButton" name="startBtn"><property name="text"><string>启动任务</string></property></widget></item></layout></widget></widget>
</ui>

代码核心逻辑说明

1. 多线程实现方式

采用 QObject::moveToThread 方式,将工作类 Worker 移动到子线程中执行任务,而非直接继承 QThread 并重写 run()。这种方式的优势:

  • 工作类通过信号槽与主线程通信,符合 Qt 事件驱动模型。
  • 支持多个任务在同一个线程中顺序执行(通过队列槽函数调用)。
2. 线程通信
  • 子线程→主线程:通过信号 progressUpdatedresultReady 发送进度和结果,Qt 会自动将信号排队到主线程执行(跨线程信号槽默认使用 Qt::QueuedConnection)。
  • 主线程→子线程:通过 QMetaObject::invokeMethod 调用子线程中的槽函数(startTask),确保在子线程上下文中执行。
3. 线程安全退出
  • 窗口关闭时,调用 workerThread->quit() 通知子线程退出事件循环,workerThread->wait() 等待线程完全停止,避免资源泄漏。
  • 子线程结束时,通过 connect(workerThread, &QThread::finished, worker, &QObject::deleteLater) 自动释放工作类实例。
4. 界面交互
  • 点击“启动任务”按钮后,按钮禁用(setEnabled(false)),防止重复触发。
  • 进度条(QProgressBar)实时显示任务进度,状态标签显示文字提示。

运行效果

  1. 编译运行程序,点击“启动任务”按钮。
  2. 进度条每秒更新一次(总耗时 5 秒),状态标签显示当前进度(如“进度:3/10”)。
  3. 任务完成后,状态标签显示“任务完成!总耗时:5秒”,按钮重新启用。

扩展说明

  • 耗时任务替代:可将 QThread::msleep(500) 替换为实际的耗时操作(如文件读写、网络请求、复杂计算)。
  • 多任务支持:若需执行多个独立任务,可在 Worker 类中添加多个槽函数(如 startTaskAstartTaskB),通过 invokeMethod 按需调用。
  • 线程池:若需管理多个线程,可使用 QThreadPoolQRunnable(适合短任务),但 moveToThread 更适合长时间运行的任务。

这个示例完整展示了 Qt 多线程的核心机制,包括线程创建、任务执行、跨线程通信和安全退出。

相关文章:

  • 位运算题目:安排电影院座位
  • 编专利或委托他人编专利属于学术不端行为吗?
  • crawl4ai能替代scrapy等传统爬虫框架吗?
  • 【报错】view size is not compatible with input tensor‘s size and stride
  • 编译原理头歌实验:词法分析程序设计与实现(C语言版)
  • Oracle OCP认证考试考点详解083系列12
  • SpringBoot中使用MCP和通义千问来处理和分析数据-连接本地数据库并生成实体类
  • 15前端项目----用户信息/导航守卫
  • SNMP 协议介绍、开发方法及示例
  • 【造包工具】【Xcap】精讲Xcap构造分片包(IPv4、ipv6、4G\5G等pcap均可),图解超赞超详细!!!
  • 投资逻辑与未来风险:高端PCB的黄金周期能持续多久?
  • 【Linux网络】网络命令
  • mongodb升级、改单节点模式
  • 矢量网络分析仪测驻波比:从原理到实战操作全解析
  • Nacos源码—6.Nacos升级gRPC分析一
  • 【redis】分片方案
  • 数据结构(二)——线性表的链式表示和实现
  • 关键字where
  • STM32智能刷卡消费系统(uC/OS-III)
  • LeetCode 11.盛最多水的容器 (Java)
  • 图忆|红场阅兵:俄罗斯30年来的卫国战争胜利日阅兵式
  • “爱鸟周”为何不能像FI和花展那样“市区联动”
  • 美众议院通过法案将“墨西哥湾”更名为“美国湾”
  • 教育部、国家发改委联合启动实施教师教育能力提升工程
  • 视频丨习近平主席出席俄方在机场举行的迎宾仪式
  • 保利发展前4个月销售额约876亿元,单月斥资128亿元获4个项目