Qt多线程学习笔记
一、核心组件
| 组件/变量 | 作用 |
|---|
QtConcurrent::run | 快速创建子线程,执行后台任务 |
QFuture<bool> | 管理后台任务状态和返回值 |
QFutureWatcher<bool> | 监控任务完成状态,触发主线程回调 |
QAtomicInt m_forceStop | 线程安全终止标志(替代std::atomic) |
QMutex m_progressMutex | 保护共享进度m_currentProgress,避免竞争 |
QMetaObject::invokeMethod | 跨线程更新UI(子线程→主线程) |
| 纯代码UI组件 | 无.ui文件,通过代码创建布局和控件 |
二、核心使用流程
1. 初始化
- 纯代码创建UI(进度条、按钮、标签+布局);
- 绑定
QFutureWatcher的finished信号到回调函数; - 初始化线程安全变量(
m_forceStop=0、m_currentProgress=0)。
2. 启动任务
- 重置进度和UI状态;
- 禁用启动按钮、启用停止按钮;
- 用
QtConcurrent::run提交backgroundTask到子线程; QFutureWatcher绑定QFuture监控任务。
3. 后台任务执行(子线程)
- 循环100步模拟耗时计算;
- 每步检查
m_forceStop(终止标志)和线程中断请求,满足则退出; - 用
QMutexLocker保护m_currentProgress更新(避免竞争); - 调用
updateProgress跨线程更新UI; QThread::msleep(50)控制任务速度。
4. 停止任务
m_forceStop.store(true)设置终止标志;m_taskFuture.cancel()取消任务,waitForFinished()等待线程退出;- 更新UI状态,恢复按钮可用性;
- 断开Watcher连接(冗余但代码保留),解绑Future。
5. 任务完成(主线程回调)
- 线程安全获取任务返回值;
- 更新状态标签,弹出完成提示(成功/中断);
- 恢复按钮状态。
三、关键注意点
- 线程安全:
- 共享数据(
m_currentProgress)用QMutex保护,读写均需加锁; - 终止标志用
QAtomicInt(Qt原子类型),避免多线程读写冲突。
- 跨线程UI更新:
- 子线程不能直接操作UI,必须通过
QMetaObject::invokeMethod+Qt::QueuedConnection切换到主线程。
- 资源释放:
- 析构函数调用
on_stopBtn_clicked(),确保线程退出后再释放资源; - 中文乱码解决:
#pragma execution_character_set("utf-8")。
- 任务终止响应:
- 后台任务内层循环也需检查终止标志,避免长时间阻塞不响应停止指令。
四、代码核心逻辑说明
1. 后台任务核心(backgroundTask)
for (int i = 0; i <= 100; ++i) {if (m_forceStop.load() || QThread::currentThread()->isInterruptionRequested()) {return false;}volatile long long sum = 0;for (long long j = 0; j < 1000000; ++j) {if (m_forceStop.load() || ...) return false; sum += j;}QMutexLocker locker(&m_progressMutex);m_currentProgress = i;updateProgress(i);
}
2. 跨线程UI更新(updateProgress)
QMetaObject::invokeMethod(this, [this, progress]() {ui.progressBar->setValue(progress);ui.statusLabel->setText(QString("状态:运行中...%1%").arg(progress));
}, Qt::QueuedConnection);
3. 停止任务逻辑(on_stopBtn_clicked)
m_forceStop.store(true);
if (m_taskFuture.isRunning()) {m_taskFuture.cancel(); m_taskFuture.waitForFinished(); ui.statusLabel->setText(...) ;
}
五.完整Demo
#ifndef QTTHREADMINDEMO_H
#define QTTHREADMINDEMO_H#include <QWidget>
#include <QFuture>
#include <QFutureWatcher>
#include <QMutex>
#include <atomic>
#include <QProgressBar>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QThread>
#include <QtConcurrent> // 添加QtConcurrent头文件
#include <QDebug>
//解决中文乱码
#pragma execution_character_set("utf-8")class QtThreadMinDemo : public QWidget
{Q_OBJECTpublic:QtThreadMinDemo(QWidget *parent = nullptr);~QtThreadMinDemo();private slots:void on_startBtn_clicked(); // 启动任务void on_stopBtn_clicked(); // 停止任务void on_taskFinished(); // 任务完成回调private:// 纯代码创建UIvoid createUI();// 后台任务(子线程执行)bool backgroundTask();// 跨线程更新进度UIvoid updateProgress(int progress);// UI组件(结构体封装,避免成员变量过多)struct UI {QProgressBar *progressBar;QLabel *statusLabel;QPushButton *startBtn;QPushButton *stopBtn;} ui;// 多线程核心变量QFuture<bool> m_taskFuture; // 管理后台任务QFutureWatcher<bool> m_taskWatcher; // 监控任务状态//std::atomic<bool> m_forceStop; // 线程安全终止标志QMutex m_progressMutex; // 保护进度数据的互斥锁int m_currentProgress; // 共享进度数据QAtomicInt m_forceStop;
};#endif // QTTHREADMINDEMO_H
#include "QtThreadMinDemo.h"QtThreadMinDemo::QtThreadMinDemo(QWidget *parent): QWidget(parent), m_forceStop(false), m_currentProgress(0)
{// 1. 创建UI(纯代码)createUI();// 2. 初始化窗口setWindowTitle("Qt多线程最小Demo(纯代码UI)");setFixedSize(400, 180); // 固定窗口大小// 3. 绑定任务完成信号connect(&m_taskWatcher, &QFutureWatcher<bool>::finished, this, &QtThreadMinDemo::on_taskFinished);
}QtThreadMinDemo::~QtThreadMinDemo()
{// 安全停止任务,释放资源on_stopBtn_clicked();// 断开Watcher连接,避免野指针m_taskWatcher.disconnect();m_taskWatcher.setFuture(QFuture<bool>());
}// 纯代码创建UI组件和布局
void QtThreadMinDemo::createUI()
{// 1. 创建UI组件ui.progressBar = new QProgressBar(this);ui.progressBar->setRange(0, 100);ui.progressBar->setValue(0);ui.statusLabel = new QLabel(this);ui.statusLabel->setText("状态:未启动");ui.startBtn = new QPushButton("启动任务", this);ui.stopBtn = new QPushButton("停止任务", this);ui.stopBtn->setEnabled(false); // 初始禁用停止按钮// 2. 创建布局QVBoxLayout *mainLayout = new QVBoxLayout(this);mainLayout->setSpacing(20);mainLayout->setContentsMargins(30, 20, 30, 20); // 内边距QHBoxLayout *btnLayout = new QHBoxLayout();btnLayout->setSpacing(40);btnLayout->addWidget(ui.startBtn);btnLayout->addWidget(ui.stopBtn);// 3. 组装布局mainLayout->addWidget(ui.progressBar);mainLayout->addWidget(ui.statusLabel);mainLayout->addLayout(btnLayout);// 4. 绑定按钮点击信号connect(ui.startBtn, &QPushButton::clicked, this, &QtThreadMinDemo::on_startBtn_clicked);connect(ui.stopBtn, &QPushButton::clicked, this, &QtThreadMinDemo::on_stopBtn_clicked);
}// 启动任务按钮回调
void QtThreadMinDemo::on_startBtn_clicked()
{// 重置状态m_currentProgress = 0;// 更新UIui.progressBar->setValue(0);ui.statusLabel->setText("状态:运行中...0%");ui.startBtn->setEnabled(false);ui.stopBtn->setEnabled(true);// 提交后台任务m_taskFuture = QtConcurrent::run(this, &QtThreadMinDemo::backgroundTask);m_taskWatcher.setFuture(m_taskFuture);
}// 停止任务按钮回调
void QtThreadMinDemo::on_stopBtn_clicked()
{m_forceStop.store(true);if (m_taskFuture.isRunning()) {// 原子设置终止标志// 取消任务并等待线程退出m_taskFuture.cancel();m_taskFuture.waitForFinished();// 更新UIui.statusLabel->setText(QString("状态:已终止(进度%1%)").arg(m_currentProgress));}m_taskWatcher.disconnect();m_taskWatcher.setFuture(QFuture<bool>());// 恢复按钮状态ui.startBtn->setEnabled(true);ui.stopBtn->setEnabled(false);m_forceStop.store(false);
}// 后台任务(子线程执行)
bool QtThreadMinDemo::backgroundTask()
{qDebug() << "后台线程启动,ID:" << QThread::currentThreadId();// 模拟100步耗时计算for (int i = 0; i <= 100; ++i) {// 检查终止标志if (m_forceStop.load() || QThread::currentThread()->isInterruptionRequested()) {qDebug() << "后台线程被终止,当前进度:" << i;return false;}// 模拟耗时计算(无业务意义)volatile long long sum = 0;for (long long j = 0; j < 1000000; ++j) {// 检查终止标志if (m_forceStop.load() || QThread::currentThread()->isInterruptionRequested()) {qDebug() << "后台线程被终止,当前进度:" << i;return false;}sum += j;}// 保护共享进度数据{QMutexLocker locker(&m_progressMutex);m_currentProgress = i;}// 跨线程更新UIupdateProgress(i);// 控制任务速度QThread::msleep(50);}qDebug() << "后台线程完成,ID:" << QThread::currentThreadId();return true;
}// 跨线程更新进度UI
void QtThreadMinDemo::updateProgress(int progress)
{QMetaObject::invokeMethod(this, [this, progress]() {ui.progressBar->setValue(progress);ui.statusLabel->setText(QString("状态:运行中...%1%").arg(progress));}, Qt::QueuedConnection);
}// 任务完成回调(主线程)
void QtThreadMinDemo::on_taskFinished()
{bool success = m_taskWatcher.result();if (success) {ui.statusLabel->setText("状态:执行完成!");QMessageBox::information(this, "提示", "后台任务100%完成~");} else {ui.statusLabel->setText(QString("状态:执行中断(进度%1%)").arg(m_currentProgress));}ui.startBtn->setEnabled(true);ui.stopBtn->setEnabled(false);
}
#include "qtthreadmindemo.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);QtThreadMinDemo w;w.show();return a.exec();
}
