【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();
}
相关推荐
xcyxiner12 小时前
DicomViewer (目录调整) 2
qt
xcyxiner14 小时前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
通信小呆呆2 天前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人
H__Rick2 天前
自动对焦学习-3
人工智能·学习·计算机视觉
Daisy Lee2 天前
量化学习-第1章-什么是量化金融
学习·金融·datawhale
Alsn862 天前
等待学习-学习目录:Docker 容器安全攻防
学习·安全·docker
YM52e2 天前
买菜计算器小应用 - HarmonyOS ArkUI 开发实战-PC版本
学习·华为·harmonyos·鸿蒙·鸿蒙系统
小雨下雨的雨2 天前
HarmonyOS ArkUI训练营入门-组件掌握系列-Animation 动画效果实现-PC版本
学习·华为·harmonyos·鸿蒙
闪闪发亮的小星星2 天前
高斯光以及高斯光公式解释
笔记
桥田智能3 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构