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)
cpp
复制代码
// 核心逻辑:循环计算+终止检查+进度更新
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;
// 跨线程更新UI
updateProgress(i);
}
2. 跨线程UI更新(updateProgress)
cpp
复制代码
QMetaObject::invokeMethod(this, [this, progress]() {
// 主线程执行UI操作(队列连接确保线程安全)
ui.progressBar->setValue(progress);
ui.statusLabel->setText(QString("状态:运行中...%1%").arg(progress));
}, Qt::QueuedConnection);
3. 停止任务逻辑(on_stopBtn_clicked)
cpp
复制代码
m_forceStop.store(true); // 设终止标志
if (m_taskFuture.isRunning()) {
m_taskFuture.cancel(); // 取消任务
m_taskFuture.waitForFinished(); // 等待线程退出(避免僵尸线程)
ui.statusLabel->setText(...) ; // 更新终止状态
}
五.完整Demo
c++
复制代码
#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_OBJECT
public:
QtThreadMinDemo(QWidget *parent = nullptr);
~QtThreadMinDemo();
private slots:
void on_startBtn_clicked(); // 启动任务
void on_stopBtn_clicked(); // 停止任务
void on_taskFinished(); // 任务完成回调
private:
// 纯代码创建UI
void createUI();
// 后台任务(子线程执行)
bool backgroundTask();
// 跨线程更新进度UI
void 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
c++
复制代码
#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;
// 更新UI
ui.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();
// 更新UI
ui.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;
}
// 跨线程更新UI
updateProgress(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);
}
c++
复制代码
#include "qtthreadmindemo.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtThreadMinDemo w;
w.show();
return a.exec();
}