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

Qt多线程学习初级指南

       

一、引言部分

1. 多线程编程的重要性

在当今计算环境中,多线程编程已成为开发高性能应用程序的关键技术。现代应用程序面临着三大挑战:

  1. GUI响应性:用户界面需要保持流畅响应,即使在进行后台计算时

  2. 多核利用率:随着多核CPU的普及,单线程程序无法充分利用硬件资源

  3. 实时处理:音视频处理、实时数据采集等场景需要并发处理能力

QT作为跨平台应用框架,在Linux系统下提供了完善的多线程支持。典型的应用场景包括:

  • 后台文件处理(如大型日志分析)

  • 网络通信(同时维护多个连接)

  • 数据采集与处理(工业控制领域)

  • 图形渲染(分离UI线程与渲染线程)

2. QT多线程的优势

QT的多线程实现具有以下独特优势:

信号槽机制

// 自动跨线程的信号槽连接
connect(workerThread, &WorkerThread::resultReady,mainWindow, &MainWindow::handleResult, Qt::AutoConnection);

内存管理

  • 基于QObject的父子关系自动管理线程生命周期

  • 线程退出时自动清理子对象

平台抽象

  • 统一接口适用于Linux/Windows/macOS等平台

  • 底层自动选择最佳实现(如Linux下使用pthread)

二、QT多线程基础

1. 核心类解析

QThread关键API

// 基本使用
QThread *thread = new QThread;
thread->start();  // 开始执行
thread->wait();   // 等待结束// 重要信号
void started();   // 线程启动时发射
void finished();  // 线程结束时发射

同步工具对比

类名适用场景示例
QMutex保护简单临界区计数器访问保护
QReadWriteLock读多写少场景配置数据访问
QSemaphore资源池管理数据库连接池
QWaitCondition线程间条件等待生产者-消费者模型

2. 实现方式对比

继承QThread方式

class MyThread : public QThread {
protected:void run() override {// 线程执行逻辑}
};

MoveToThread方式

QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &Worker::doWork);

选择标准

  • 需要控制运行流程 → 继承QThread

  • 事件驱动型任务 → MoveToThread

  • 短时并发任务 → QThreadPool

三、实战案例解析

        三线程demo

         1.运行结果             2.类关系图

        

      

         3.关系实现细节

                线程安全停止:

void WorkerThread::requestStop() {QMutexLocker locker(&m_mutex);  // RAII风格锁m_stopRequested = true;
}void WorkerThread::run() {while(true) {{QMutexLocker locker(&m_mutex);if(m_stopRequested) break;}// 工作逻辑...}
}

        跨线程UI更新

// WorkerThread中
emit statusUpdated("Processing item " + QString::number(i));// MainWindow中
connect(thread, &WorkerThread::statusUpdated,this, [this, threadId](const QString &msg){m_labels[threadId]->setText(msg);  // 自动排队到UI线程执行
});

           4.详细代码

        workerthread.h

#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H#include <QThread>
#include <QString>
#include <QMutex>/*** @brief 工作线程类,继承自QThread** 演示QT5中创建自定义线程类的标准方式*/
class WorkerThread : public QThread
{Q_OBJECT
public:/*** @brief 构造函数* @param threadName 线程名称,用于标识* @param parent 父对象指针*/explicit WorkerThread(const QString &threadName, QObject *parent = nullptr);/*** @brief 析构函数 - 确保线程安全退出*/~WorkerThread();/*** @brief 安全停止线程*/void requestStop();signals:/*** @brief 线程状态更新信号* @param message 状态消息*/void statusUpdated(const QString &message);protected:/*** @brief 线程主执行函数*/void run() override;private:QString m_threadName;   // 线程标识名称bool m_stopRequested;   // 停止请求标志QMutex m_mutex;         // 互斥锁保护共享数据
};#endif // WORKERTHREAD_H

          workerthread.c

#include "workerthread.h"
#include <QDebug>
#include <QTime>
#include <QMutexLocker>WorkerThread::WorkerThread(const QString &threadName, QObject *parent): QThread(parent),m_threadName(threadName),m_stopRequested(false)
{qDebug() << "WorkerThread created:" << m_threadName;
}WorkerThread::~WorkerThread()
{// 确保线程安全退出requestStop();if(isRunning()){wait(500);  // 等待500ms线程结束if(isRunning()){qWarning() << m_threadName << "thread not stopped properly, terminating!";terminate();  // 最后手段强制终止wait();}}qDebug() << "WorkerThread destroyed:" << m_threadName;
}void WorkerThread::requestStop()
{QMutexLocker locker(&m_mutex);m_stopRequested = true;
}void WorkerThread::run()
{qDebug() << m_threadName << "thread started";emit statusUpdated(m_threadName + ": 线程启动");int taskCount = 0;while(true){// 检查停止请求(线程安全方式){QMutexLocker locker(&m_mutex);if(m_stopRequested) break;}// 模拟工作负载 (随机500-1500ms)int delay = 500 + (qrand() % 1000);msleep(delay);// 更新状态++taskCount;QString msg = QString("%1: 完成任务 #%2 (耗时%3ms)").arg(m_threadName).arg(taskCount).arg(delay);emit statusUpdated(msg);}emit statusUpdated(m_threadName + ": 线程停止");qDebug() << m_threadName << "thread finished";
}

        mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QVector>
#include "workerthread.h"
#include <QLabel>/*** @brief 主窗口类** 演示如何管理多个工作线程并与UI交互*/
class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:// 启动所有线程void startAllThreads();// 停止所有线程void stopAllThreads();// 更新线程状态显示void updateThreadStatus(int threadId, const QString &message);private:// 初始化UI组件void initUI();// 初始化工作线程void initThreads();// 连接信号槽void connectSignals();// UI组件QVector<QLabel*> m_statusLabels;    // 线程状态标签QPushButton* m_startButton;         // 启动按钮QPushButton* m_stopButton;          // 停止按钮QVBoxLayout* m_mainLayout;          // 主布局// 线程管理QVector<WorkerThread*> m_threads;   // 工作线程集合static const int THREAD_COUNT = 3;  // 线程数量
};#endif // MAINWINDOW_H

         mianwindow.c

#include "mainwindow.h"
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
#include <QPushButton>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent),m_startButton(nullptr),m_stopButton(nullptr),m_mainLayout(nullptr)
{// 设置窗口属性setWindowTitle("QT5.12 多线程演示");resize(500, 350);// 初始化UIinitUI();// 初始化线程initThreads();// 连接信号槽connectSignals();
}MainWindow::~MainWindow()
{// 停止并删除所有线程stopAllThreads();qDeleteAll(m_threads);m_threads.clear();
}void MainWindow::initUI()
{// 创建中央部件QWidget *centralWidget = new QWidget(this);setCentralWidget(centralWidget);// 创建主布局m_mainLayout = new QVBoxLayout(centralWidget);m_mainLayout->setSpacing(10);m_mainLayout->setContentsMargins(15, 15, 15, 15);// 创建状态标签for (int i = 0; i < THREAD_COUNT; ++i){QLabel *label = new QLabel(QString("线程 %1: 等待启动").arg(i+1), this);label->setStyleSheet("QLabel { font-weight: bold; }");m_statusLabels.append(label);m_mainLayout->addWidget(label);}// 添加弹性空间m_mainLayout->addStretch();// 创建控制按钮m_startButton = new QPushButton("启动所有线程", this);m_startButton->setFixedHeight(35);m_stopButton = new QPushButton("停止所有线程", this);m_stopButton->setFixedHeight(35);m_stopButton->setEnabled(false);// 添加按钮到布局m_mainLayout->addWidget(m_startButton);m_mainLayout->addWidget(m_stopButton);
}void MainWindow::initThreads()
{// 创建指定数量的工作线程for (int i = 0; i < THREAD_COUNT; ++i){WorkerThread *thread = new WorkerThread(QString("线程 %1").arg(i+1), this);m_threads.append(thread);}
}void MainWindow::connectSignals()
{// 连接按钮信号connect(m_startButton, &QPushButton::clicked,this, &MainWindow::startAllThreads);connect(m_stopButton, &QPushButton::clicked,this, &MainWindow::stopAllThreads);// 连接线程信号for (int i = 0; i < m_threads.size(); ++i){// 使用lambda捕获线程IDconnect(m_threads[i], &WorkerThread::statusUpdated,this, [this, i](const QString &msg){updateThreadStatus(i, msg);});}
}void MainWindow::startAllThreads()
{for (int i = 0; i < m_threads.size(); ++i){if (!m_threads[i]->isRunning()){m_threads[i]->start();}}// 更新按钮状态m_startButton->setEnabled(false);m_stopButton->setEnabled(true);
}void MainWindow::stopAllThreads()
{for (auto thread : m_threads){if (thread->isRunning()){thread->requestStop();}}// 更新按钮状态m_startButton->setEnabled(true);m_stopButton->setEnabled(false);
}void MainWindow::updateThreadStatus(int threadId, const QString &message)
{if (threadId >= 0 && threadId < m_statusLabels.size()){m_statusLabels[threadId]->setText(message);}
}

        main.c

#include "mainwindow.h"#include <QApplication>
#include <QTime>int main(int argc, char *argv[])
{// 设置应用程序属性QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);QApplication app(argc, argv);// 设置随机种子qsrand(QTime::currentTime().msec());// 创建并显示主窗口MainWindow window;window.show();return app.exec();
}

http://www.xdnf.cn/news/108937.html

相关文章:

  • lerobot[act解析]
  • 【浙江大学DeepSeek公开课】走向数字社会:从DeepSeek到群体智慧
  • JDK(Ubuntu 18.04.6 LTS)安装笔记
  • OrbStack 全面介绍:功能、安装与使用指南
  • Java 拦截器完全指南:原理、实战与最佳实践
  • 【Flutter高效开发】GetX指南:一文学会状态管理、路由与依赖注入
  • BEVFormer论文解读
  • 如何实现应用创新:一个实用框架
  • Java 开发瓶颈破局:飞算 JavaAI 如何一站式生成标准化项目结构?
  • 本节课课堂总结
  • kotlin与MVVM结合使用总结(一)
  • 按照文本每行匹配文件复制到指定位置
  • CONDA:用于 Co-Salient 目标检测的压缩深度关联学习(总结)
  • 开源 RAG 引擎:文档理解精准、检索高效、可视化干预灵活,一站式搞定
  • Kappa架构:简化大数据实时流处理的创新方案
  • 【Luogu】动态规划二
  • 2025.4.27机器学习笔记:文献阅读
  • 类和对象(中)
  • Spring AI 会话记忆(笔记)
  • 【3.2】pod详解—— Pod的相位(phase)状态(status)
  • Linux常用指令
  • 小刚说C语言刷题——1338求圆环的面积
  • C++二分法详解
  • el-table 目录树列表本地实现模糊查询
  • Linux部署Redis主从
  • 天梯-零头就抹了吧
  • 实操Obsidian+Ollama+deepseek构建本地知识库
  • C语言五子棋项目
  • [计算机科学#1]:计算机的前世今生,从算盘到IBM的演变之路
  • flex布局说明