【Qt】多线程学习笔记

Qt多线程学习笔记

一、核心组件

组件/变量 作用
QtConcurrent::run 快速创建子线程,执行后台任务
QFuture<bool> 管理后台任务状态和返回值
QFutureWatcher<bool> 监控任务完成状态,触发主线程回调
QAtomicInt m_forceStop 线程安全终止标志(替代std::atomic)
QMutex m_progressMutex 保护共享进度m_currentProgress,避免竞争
QMetaObject::invokeMethod 跨线程更新UI(子线程→主线程)
纯代码UI组件 无.ui文件,通过代码创建布局和控件

二、核心使用流程

1. 初始化

  • 纯代码创建UI(进度条、按钮、标签+布局);
  • 绑定QFutureWatcherfinished信号到回调函数;
  • 初始化线程安全变量(m_forceStop=0m_currentProgress=0)。

2. 启动任务

  1. 重置进度和UI状态;
  2. 禁用启动按钮、启用停止按钮;
  3. QtConcurrent::run提交backgroundTask到子线程;
  4. QFutureWatcher绑定QFuture监控任务。

3. 后台任务执行(子线程)

  1. 循环100步模拟耗时计算;
  2. 每步检查m_forceStop(终止标志)和线程中断请求,满足则退出;
  3. QMutexLocker保护m_currentProgress更新(避免竞争);
  4. 调用updateProgress跨线程更新UI;
  5. QThread::msleep(50)控制任务速度。

4. 停止任务

  1. m_forceStop.store(true)设置终止标志;
  2. m_taskFuture.cancel()取消任务,waitForFinished()等待线程退出;
  3. 更新UI状态,恢复按钮可用性;
  4. 断开Watcher连接(冗余但代码保留),解绑Future。

5. 任务完成(主线程回调)

  • 线程安全获取任务返回值;
  • 更新状态标签,弹出完成提示(成功/中断);
  • 恢复按钮状态。

三、关键注意点

  1. 线程安全
    • 共享数据(m_currentProgress)用QMutex保护,读写均需加锁;
    • 终止标志用QAtomicInt(Qt原子类型),避免多线程读写冲突。
  2. 跨线程UI更新
    • 子线程不能直接操作UI,必须通过QMetaObject::invokeMethod+Qt::QueuedConnection切换到主线程。
  3. 资源释放
    • 析构函数调用on_stopBtn_clicked(),确保线程退出后再释放资源;
    • 中文乱码解决:#pragma execution_character_set("utf-8")
  4. 任务终止响应
    • 后台任务内层循环也需检查终止标志,避免长时间阻塞不响应停止指令。

四、代码核心逻辑说明

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();
}
相关推荐
点云SLAM25 分钟前
Exhaustive英文单词学习
人工智能·学习·exhaustive·英文单词学习·雅思备课·全面的
浮游本尊42 分钟前
React 18.x 学习计划 - 第八天:React测试
前端·学习·react.js
麦麦在写代码1 小时前
前端学习1
前端·学习
笨鸟笃行1 小时前
人工智能备考——2.1.1-2.1.5总结
人工智能·学习
TravisBytes1 小时前
一次 Qt 网络程序诡异崩溃排查:从 Breakpad 堆栈到 lambda 捕获悬空引用
网络·qt·php
AA陈超1 小时前
ASC学习笔记0012:查找现有的属性集,如果不存在则断言
笔记·学习
wshzd2 小时前
LLM之Agent(二十八)|AI音视频转笔记方法揭秘
人工智能·笔记
7***53342 小时前
免费的云原生学习资源,K8s+Docker
学习·云原生·kubernetes
The_Second_Coming2 小时前
Python 学习笔记:基础篇
运维·笔记·python·学习