在 Qt 开发中,面对复杂计算、耗时 IO 操作(如文件下载、数据解析)时,单线程往往会导致界面卡顿、响应迟缓,严重影响用户体验。而多线程技术能让程序 “并行” 处理多个任务,在保证界面流畅的同时提升执行效率。Qt 封装了强大的
QThread类,提供了跨平台的多线程解决方案,无需关注底层操作系统的线程实现差异。本文将从基础概念出发,手把手教你掌握 Qt 多线程的使用技巧、核心 API、线程创建流程以及线程安全保障,让你轻松搞定并发编程!下面就让我们正式开始吧!
单线程程序的执行流程是线性的,所有任务按顺序依次执行。当遇到耗时操作(如大数据计算、网络请求、文件读写)时,主线程会被阻塞,导致界面无法响应鼠标点击、键盘输入等用户操作,出现 “假死” 现象。
多线程的核心价值在于任务并行执行:将耗时任务分配到子线程中处理,主线程专注于界面渲染和用户交互,从而实现 “界面流畅 + 任务高效执行” 的双赢。例如:
Qt 的QThread类封装了底层线程操作,相比原生 C++ 线程(std::thread),具有以下优势:
QMutex、QWaitCondition等同步工具,避免线程安全问题。 QThread是 Qt 多线程的核心类,封装了线程的创建、启动、管理等功能。以下是最常用的 API,按功能分类整理,方便快速查阅。
API 函数 | 功能说明 | 关键细节 |
|---|---|---|
void start(Priority priority = InheritPriority) | 启动线程,调用run()函数 | 线程状态变为 “运行中”,若已运行则无效果;priority指定线程优先级 |
void terminate() | 强制终止线程 | 不推荐优先使用,可能导致资源泄漏,需配合wait()确保线程终止 |
bool wait(unsigned long time = ULONG_MAX) | 阻塞当前线程,等待目标线程结束 | time为等待超时时间(毫秒),默认无限等待;返回true表示线程正常结束 |
void exit(int returnCode = 0) | 退出线程事件循环 | returnCode为退出码,0 表示正常退出 |
void quit() | 等价于exit(0),退出线程事件循环 | 仅对开启事件循环的线程有效(如使用exec()) |
bool isRunning() const | 判断线程是否正在运行 | 返回true表示线程处于运行状态 |
bool isFinished() const | 判断线程是否已结束 | 返回true表示线程已退出(run()函数执行完毕) |
API 函数 | 功能说明 | 注意事项 |
|---|---|---|
static void sleep(unsigned long sec) | 使当前线程休眠指定秒数 | 静态函数,作用于当前执行线程 |
static void msleep(unsigned long msec) | 使当前线程休眠指定毫秒数 | 精度依赖操作系统,可能存在微小误差 |
static void usleep(unsigned long usec) | 使当前线程休眠指定微秒数 | 适用于高精度休眠场景 |
static QThread *currentThread() | 返回当前执行线程的指针 | 常用于打印线程 ID、判断线程身份 |
static Qt::HANDLE currentThreadId() | 返回当前线程的系统原生 ID | 用于与系统原生线程 API 交互 |
QThread::Priority枚举定义了线程优先级,影响操作系统的调度策略,常用值如下:
QThread::IdlePriority:最低优先级,仅当无其他线程运行时执行;QThread::LowestPriority:较低优先级;QThread::NormalPriority:默认优先级;QThread::HighestPriority:较高优先级;QThread::TimeCriticalPriority:最高优先级,尽量占用 CPU 资源。 QThread提供了关键信号,用于监听线程状态变化:
void started():线程启动时触发(run()函数执行前);void finished():线程结束时触发(run()函数执行完毕后);void terminated():线程被terminate()强制终止时触发。 Qt 创建线程的核心流程是:自定义线程类继承QThread → 重写run()函数(线程入口) → 实例化线程对象 → 调用start()启动线程。下面通过多个实战案例,详解不同场景下的线程使用方法。
实现功能:子线程每隔 1 秒发送当前时间到主线程,主线程更新界面显示。
首先创建Qt项目,并编辑UI界面:
新建TimeThread类,继承QThread:
重写run()函数,通过信号发送时间数据:
timethread.h
#ifndef TIMETHREAD_H
#define TIMETHREAD_H
#include <QThread>
#include <QTime>
#include <QObject>
class TimeThread : public QThread
{
Q_OBJECT // 必须添加,支持信号槽
public:
explicit TimeThread(QObject *parent = nullptr);
protected:
// 线程入口函数,线程启动后自动执行
void run() override;
signals:
// 发送时间信号,主线程接收并更新UI
void sendTime(QString currentTime);
};
#endif // TIMETHREAD_Htimethread.cpp
#include "timethread.h"
#include <QDebug>
TimeThread::TimeThread(QObject *parent) : QThread(parent)
{
}
void TimeThread::run()
{
qDebug() << "子线程启动,线程ID:" << currentThreadId();
// 循环发送时间,每隔1秒一次
while (1)
{
// 获取当前时间,格式化为"hh:mm:ss"
QString timeStr = QTime::currentTime().toString("hh:mm:ss");
// 发送信号到主线程
emit sendTime(timeStr);
// 线程休眠1秒
sleep(1);
}
} 在主窗口(Widget)中实例化TimeThread对象,绑定信号槽,接收子线程发送的时间并更新界面。
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "timethread.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
// 启动线程按钮点击槽函数
void on_startBtn_clicked();
// 接收子线程时间信号的槽函数
void showCurrentTime(QString timeStr);
private:
Ui::Widget *ui;
TimeThread *timeThread; // 线程对象指针
};
#endif // WIDGET_Hwidget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("Qt多线程计时示例");
// 实例化线程对象
timeThread = new TimeThread(this);
// 绑定子线程信号到主线程槽函数
// 注意:跨线程信号槽默认使用QueuedConnection,确保线程安全
connect(timeThread, &TimeThread::sendTime, this, &Widget::showCurrentTime);
qDebug() << "主线程ID:" << QThread::currentThreadId();
}
Widget::~Widget()
{
// 停止线程并等待结束,避免资源泄漏
timeThread->terminate();
timeThread->wait();
delete ui;
}
void Widget::on_startBtn_clicked()
{
if (!timeThread->isRunning())
{
timeThread->start(); // 启动线程
ui->startBtn->setText("线程已启动");
ui->startBtn->setEnabled(false);
}
}
void Widget::showCurrentTime(QString timeStr)
{
// 主线程更新UI
ui->timeLabel->setText(timeStr);
ui->timeLabel->setStyleSheet("font-size: 36px; text-align: center;");
}timeLabel每秒更新一次当前时间;run()函数是线程的入口,线程启动后自动执行,所有耗时操作应放在此处;ui->timeLabel->setText()),必须通过信号槽机制通知主线程更新;terminate()强制终止(或让run()函数正常退出),并调用wait()等待线程结束,避免资源泄漏。当多个线程同时访问共享资源(如全局变量、类成员变量)时,会出现 “线程竞争” 问题,导致数据错乱。下面通过案例演示线程竞争现象,再引入同步机制解决。
创建两个子线程,同时对一个全局变量num进行自增操作,观察数据错乱现象。
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QMutex>
#include <QDebug>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
protected:
void run() override;
private:
static int num; // 静态变量,多个线程共享
static QMutex mutex; // 静态互斥锁,保护共享资源
};
// 初始化静态变量
int MyThread::num = 0;
QMutex MyThread::mutex;
#endif // MYTHREAD_Hmythread.cpp
#include "mythread.h"
MyThread::MyThread(QObject *parent) : QThread(parent)
{
}
void MyThread::run()
{
while (1)
{
// 未加锁,存在线程竞争
num++;
qDebug() << "线程" << currentThreadId() << ":num = " << num;
msleep(500); // 休眠500毫秒,放大竞争概率
}
}mainwindow.cpp(主线程启动两个子线程)
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mythread.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("线程竞争演示");
// 创建两个线程
MyThread *t1 = new MyThread(this);
MyThread *t2 = new MyThread(this);
// 启动线程
t1->start();
t2->start();
}
MainWindow::~MainWindow()
{
delete ui;
}控制台输出如下(数据错乱):
线程 0x7f8c3c000b80 :num = 1
线程 0x7f8c3b800000 :num = 2
线程 0x7f8c3c000b80 :num = 3
线程 0x7f8c3b800000 :num = 3 // 数据重复,出现竞争
线程 0x7f8c3c000b80 :num = 4
线程 0x7f8c3b800000 :num = 5 num++看似是一个操作,实则包含三个步骤:
num的当前值;num。 当两个线程同时执行时,可能出现 “线程 A 读取值后,线程 B 也读取同一个值,两者加 1 后写回,导致num只增加 1” 的情况,即线程竞争。
为解决线程竞争,需使用互斥锁(QMutex) 保护共享资源。互斥锁保证同一时间只有一个线程能访问共享资源,其他线程需等待锁释放后才能访问。
修改mythread.cpp,在访问num前后添加锁操作:
void MyThread::run()
{
while (1)
{
mutex.lock(); // 上锁,若已上锁则阻塞等待
// 临界区:访问共享资源
num++;
qDebug() << "线程" << currentThreadId() << ":num = " << num;
mutex.unlock(); // 解锁,释放资源
msleep(500);
}
}控制台输出如下(数据正常递增):
线程 0x7f8c3c000b80 :num = 1
线程 0x7f8c3b800000 :num = 2
线程 0x7f8c3c000b80 :num = 3
线程 0x7f8c3b800000 :num = 4
线程 0x7f8c3c000b80 :num = 5
线程 0x7f8c3b800000 :num = 6 手动调用lock()和unlock()可能因异常、return 等导致解锁遗漏,引发死锁。QMutexLocker是QMutex的辅助类,采用 RAII(资源获取即初始化)机制,自动管理锁的生命周期:
修改mythread.cpp,使用QMutexLocker:
void MyThread::run()
{
while (1)
{
// 构造时自动上锁,作用域结束时自动解锁
QMutexLocker locker(&mutex);
num++;
qDebug() << "线程" << currentThreadId() << ":num = " << num;
msleep(500);
}
}QMutexLocker是推荐用法,简化代码并避免死锁风险。除了互斥锁,Qt 还提供了条件变量、信号量、读写锁等高级同步机制,适用于不同场景。
条件变量用于线程间的 “通信”,让一个线程等待某个条件满足后再继续执行。例如:线程 A 等待线程 B 完成数据准备后,再开始处理数据。
void wait(QMutex *mutex):释放互斥锁,让线程进入等待状态,直到被唤醒;void wakeOne():唤醒一个等待的线程;void wakeAll():唤醒所有等待的线程。producerconsumer.h
#ifndef PRODUCERCONSUMER_H
#define PRODUCERCONSUMER_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QList>
#include <QDebug>
// 共享缓冲区容量
#define BUFFER_SIZE 5
class Producer : public QThread
{
Q_OBJECT
public:
Producer(QMutex *mutex, QWaitCondition *cond, QList<int> *buffer, QObject *parent = nullptr);
void run() override;
private:
QMutex *m_mutex;
QWaitCondition *m_cond;
QList<int> *m_buffer;
};
class Consumer : public QThread
{
Q_OBJECT
public:
Consumer(QMutex *mutex, QWaitCondition *cond, QList<int> *buffer, QObject *parent = nullptr);
void run() override;
private:
QMutex *m_mutex;
QWaitCondition *m_cond;
QList<int> *m_buffer;
};
#endif // PRODUCERCONSUMER_Hproducerconsumer.cpp
#include "producerconsumer.h"
// 生产者线程
Producer::Producer(QMutex *mutex, QWaitCondition *cond, QList<int> *buffer, QObject *parent)
: QThread(parent), m_mutex(mutex), m_cond(cond), m_buffer(buffer)
{
}
void Producer::run()
{
int data = 0;
while (1)
{
QMutexLocker locker(m_mutex);
// 缓冲区满,等待消费者取走数据
while (m_buffer->size() >= BUFFER_SIZE)
{
qDebug() << "缓冲区满,生产者等待...";
m_cond->wait(m_mutex); // 释放锁,进入等待
}
// 生产数据,存入缓冲区
data++;
m_buffer->append(data);
qDebug() << "生产者生产数据:" << data << ",缓冲区大小:" << m_buffer->size();
// 唤醒消费者(缓冲区有数据了)
m_cond->wakeOne();
msleep(1000); // 模拟生产耗时
}
}
// 消费者线程
Consumer::Consumer(QMutex *mutex, QWaitCondition *cond, QList<int> *buffer, QObject *parent)
: QThread(parent), m_mutex(mutex), m_cond(cond), m_buffer(buffer)
{
}
void Consumer::run()
{
while (1)
{
QMutexLocker locker(m_mutex);
// 缓冲区空,等待生产者生产数据
while (m_buffer->isEmpty())
{
qDebug() << "缓冲区空,消费者等待...";
m_cond->wait(m_mutex); // 释放锁,进入等待
}
// 消费数据,从缓冲区取出
int data = m_buffer->takeFirst();
qDebug() << "消费者消费数据:" << data << ",缓冲区大小:" << m_buffer->size();
// 唤醒生产者(缓冲区有空位了)
m_cond->wakeOne();
msleep(1500); // 模拟消费耗时
}
}mainwindow.cpp(启动生产者和消费者线程)
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "producerconsumer.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("生产者-消费者模型");
// 初始化共享资源和同步工具
QMutex *mutex = new QMutex;
QWaitCondition *cond = new QWaitCondition;
QList<int> *buffer = new QList<int>;
// 创建并启动线程
Producer *producer = new Producer(mutex, cond, buffer, this);
Consumer *consumer = new Consumer(mutex, cond, buffer, this);
producer->start();
consumer->start();
}缓冲区空,消费者等待...
生产者生产数据:1 ,缓冲区大小:1
消费者消费数据:1 ,缓冲区大小:0
生产者生产数据:2 ,缓冲区大小:1
消费者消费数据:2 ,缓冲区大小:0
生产者生产数据:3 ,缓冲区大小:1
生产者生产数据:4 ,缓冲区大小:2
消费者消费数据:3 ,缓冲区大小:1
生产者生产数据:5 ,缓冲区大小:2
消费者消费数据:4 ,缓冲区大小:1
生产者生产数据:6 ,缓冲区大小:2
缓冲区满,生产者等待...
消费者消费数据:5 ,缓冲区大小:1
生产者生产数据:7 ,缓冲区大小:2wait()函数会自动释放锁,避免死锁;while循环判断条件(而非if),防止线程被虚假唤醒(操作系统层面的异常唤醒);wakeOne()唤醒一个等待线程,wakeAll()唤醒所有等待线程,根据场景选择使用。信号量是互斥锁的扩展,支持限制同时访问共享资源的线程数量(互斥锁仅允许一个线程访问)。适用于资源有限的场景(如有限的数据库连接、网络连接)。
QSemaphore(int n = 0):构造函数,n为可用资源数量;void acquire(int n = 1):获取n个资源,若资源不足则阻塞;void release(int n = 1):释放n个资源;int available() const:返回当前可用的资源数量。假设系统只有 2 个网络连接资源,创建 5 个线程,每个线程需要获取 1 个连接资源才能执行任务,执行完毕后释放资源。
semaphorethread.h
#ifndef SEMAPHORETHREAD_H
#define SEMAPHORETHREAD_H
#include <QThread>
#include <QSemaphore>
#include <QDebug>
class SemaphoreThread : public QThread
{
Q_OBJECT
public:
SemaphoreThread(QSemaphore *sem, int id, QObject *parent = nullptr);
void run() override;
private:
QSemaphore *m_sem;
int m_threadId;
};
#endif // SEMAPHORETHREAD_Hsemaphorethread.cpp
#include "semaphorethread.h"
SemaphoreThread::SemaphoreThread(QSemaphore *sem, int id, QObject *parent)
: QThread(parent), m_sem(sem), m_threadId(id)
{
}
void SemaphoreThread::run()
{
qDebug() << "线程" << m_threadId << "尝试获取资源...";
m_sem->acquire(); // 获取1个资源,资源不足则阻塞
// 资源获取成功,执行任务
qDebug() << "线程" << m_threadId << "获取资源成功,开始执行任务...";
msleep(2000); // 模拟任务耗时
qDebug() << "线程" << m_threadId << "任务执行完毕,释放资源";
m_sem->release(); // 释放1个资源
}mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "semaphorethread.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("信号量限制并发线程数");
// 信号量初始化,可用资源数量为2
QSemaphore *sem = new QSemaphore(2);
// 创建5个线程
for (int i = 1; i <= 5; ++i)
{
SemaphoreThread *thread = new SemaphoreThread(sem, i, this);
thread->start();
}
}线程 1 尝试获取资源...
线程 1 获取资源成功,开始执行任务...
线程 2 尝试获取资源...
线程 2 获取资源成功,开始执行任务...
线程 3 尝试获取资源...
线程 4 尝试获取资源...
线程 5 尝试获取资源...
线程 1 任务执行完毕,释放资源
线程 3 获取资源成功,开始执行任务...
线程 2 任务执行完毕,释放资源
线程 4 获取资源成功,开始执行任务...
线程 3 任务执行完毕,释放资源
线程 5 获取资源成功,开始执行任务...
线程 4 任务执行完毕,释放资源
线程 5 任务执行完毕,释放资源acquire()减少计数,release()增加计数;acquire()会阻塞,直到有线程释放资源;读写锁是一种优化的互斥锁,区分 “读操作” 和 “写操作”:
适用于 “读多写少” 的场景(如配置文件读取、数据查询),能提升并发效率。
void lockForRead():上读锁,允许多个线程同时读;void lockForWrite():上写锁,仅允许一个线程写;void unlock():解锁;QReadLocker:读锁辅助类,自动上锁解锁;QWriteLocker:写锁辅助类,自动上锁解锁。创建 3 个读线程和 1 个写线程,共享一个数据集合,读线程频繁查询数据,写线程定期更新数据。
rwlockthread.h
#ifndef RWLOCKTHREAD_H
#define RWLOCKTHREAD_H
#include <QThread>
#include <QReadWriteLock>
#include <QList>
#include <QDebug>
class ReadThread : public QThread
{
Q_OBJECT
public:
ReadThread(QReadWriteLock *rwLock, QList<int> *dataList, int id, QObject *parent = nullptr);
void run() override;
private:
QReadWriteLock *m_rwLock;
QList<int> *m_dataList;
int m_threadId;
};
class WriteThread : public QThread
{
Q_OBJECT
public:
WriteThread(QReadWriteLock *rwLock, QList<int> *dataList, QObject *parent = nullptr);
void run() override;
private:
QReadWriteLock *m_rwLock;
QList<int> *m_dataList;
};
#endif // RWLOCKTHREAD_Hrwlockthread.cpp
#include "rwlockthread.h"
// 读线程
ReadThread::ReadThread(QReadWriteLock *rwLock, QList<int> *dataList, int id, QObject *parent)
: QThread(parent), m_rwLock(rwLock), m_dataList(dataList), m_threadId(id)
{
}
void ReadThread::run()
{
while (1)
{
// 上读锁,自动解锁
QReadLocker locker(m_rwLock);
// 读操作:遍历数据集合
qDebug() << "读线程" << m_threadId << "开始读取,数据集合:" << *m_dataList;
msleep(1000); // 模拟读耗时
}
}
// 写线程
WriteThread::WriteThread(QReadWriteLock *rwLock, QList<int> *dataList, QObject *parent)
: QThread(parent), m_rwLock(rwLock), m_dataList(dataList)
{
}
void WriteThread::run()
{
int data = 0;
while (1)
{
// 上写锁,自动解锁
QWriteLocker locker(m_rwLock);
// 写操作:添加数据
data++;
m_dataList->append(data);
qDebug() << "写线程更新数据,添加:" << data << ",数据集合大小:" << m_dataList->size();
msleep(3000); // 模拟写耗时
}
}mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "rwlockthread.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("读写锁实战");
// 初始化共享数据和读写锁
QReadWriteLock *rwLock = new QReadWriteLock;
QList<int> *dataList = new QList<int>;
// 创建3个读线程
for (int i = 1; i <= 3; ++i)
{
ReadThread *readThread = new ReadThread(rwLock, dataList, i, this);
readThread->start();
}
// 创建1个写线程
WriteThread *writeThread = new WriteThread(rwLock, dataList, this);
writeThread->start();
}读线程 1 开始读取,数据集合:()
读线程 2 开始读取,数据集合:()
读线程 3 开始读取,数据集合:()
写线程更新数据,添加:1 ,数据集合大小:1
读线程 1 开始读取,数据集合:(1)
读线程 2 开始读取,数据集合:(1)
读线程 3 开始读取,数据集合:(1)
读线程 1 开始读取,数据集合:(1)
读线程 2 开始读取,数据集合:(1)
读线程 3 开始读取,数据集合:(1)
写线程更新数据,添加:2 ,数据集合大小:2QReadLocker和QWriteLocker简化锁管理,避免遗漏解锁。问题:子线程中直接调用ui->label->setText()等 UI 操作,程序崩溃。
原因:Qt 的 UI 控件不是线程安全的,仅允许主线程访问。
解决方案:通过信号槽机制,子线程发送信号,主线程接收信号并更新 UI(跨线程信号槽默认使用QueuedConnection,自动切换到主线程执行)。
问题:线程执行完毕后,资源未释放,导致内存泄漏。
解决方案:
deleteLater()删除线程对象;terminate()强制终止子线程,再调用wait()等待线程结束;QThreadPool)复用线程。问题:多个线程互相等待对方释放锁,导致程序卡住。
常见场景:
QMutexLocker自动解锁,避免手动解锁遗漏;问题:过度设置高优先级线程,导致低优先级线程无法执行。
解决方案:
NormalPriority); 跨线程信号槽的连接类型(Qt::ConnectionType)影响线程安全:
Qt::AutoConnection(默认):自动判断,同线程用DirectConnection,跨线程用QueuedConnection;Qt::DirectConnection:信号发送时立即执行槽函数,槽函数在发送线程执行(跨线程不安全);Qt::QueuedConnection:槽函数被放入接收线程的事件队列,稍后执行(跨线程安全);Qt::BlockingQueuedConnection:发送线程阻塞,直到槽函数执行完毕(可能导致死锁,需确保发送线程和接收线程不是同一线程)。推荐用法:跨线程信号槽使用默认的AutoConnection,或显式指定QueuedConnection。
创建和销毁线程会消耗系统资源,对于短期任务、大量任务(如网络请求、数据处理),使用线程池可复用线程,提升性能。Qt 的QThreadPool管理一组线程,自动分配任务,无需手动管理线程生命周期。
static QThreadPool *globalInstance():获取全局线程池实例;void start(QRunnable *runnable, int priority = 0):提交任务到线程池;void setMaxThreadCount(int maxThreadCount):设置线程池最大线程数;int maxThreadCount() const:获取最大线程数;bool waitForDone(unsigned long time = ULONG_MAX):等待所有任务执行完毕。创建 10 个任务,提交到线程池,线程池自动分配线程执行任务。
task.h(任务类,继承QRunnable)
#ifndef TASK_H
#define TASK_H
#include <QRunnable>
#include <QDebug>
#include <QThread>
class Task : public QRunnable
{
public:
Task(int taskId);
void run() override; // 任务执行函数
private:
int m_taskId;
};
#endif // TASK_Htask.cpp
#include "task.h"
Task::Task(int taskId) : m_taskId(taskId)
{
// 设置任务执行完毕后自动删除
setAutoDelete(true);
}
void Task::run()
{
qDebug() << "任务" << m_taskId << "开始执行,线程ID:" << QThread::currentThreadId();
// 模拟任务耗时
QThread::msleep(1000);
qDebug() << "任务" << m_taskId << "执行完毕";
}mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "task.h"
#include <QThreadPool>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("Qt线程池实战");
// 获取全局线程池实例
QThreadPool *pool = QThreadPool::globalInstance();
// 设置最大线程数为3
pool->setMaxThreadCount(3);
qDebug() << "线程池最大线程数:" << pool->maxThreadCount();
// 提交10个任务到线程池
for (int i = 1; i <= 10; ++i)
{
Task *task = new Task(i);
pool->start(task); // 提交任务
}
// 等待所有任务执行完毕(可选)
pool->waitForDone();
qDebug() << "所有任务执行完毕";
}线程池最大线程数:3
任务 1 开始执行,线程ID: 0x7f8c3c000b80
任务 2 开始执行,线程ID: 0x7f8c3b800000
任务 3 开始执行,线程ID: 0x7f8c3b000000
任务 1 执行完毕
任务 4 开始执行,线程ID: 0x7f8c3c000b80
任务 2 执行完毕
任务 5 开始执行,线程ID: 0x7f8c3b800000
任务 3 执行完毕
任务 6 开始执行,线程ID: 0x7f8c3b000000
...
所有任务执行完毕QRunnable,重写run()函数(任务执行入口);setAutoDelete(true)设置任务执行完毕后自动删除,避免内存泄漏;setMaxThreadCount()设置最大线程数,建议根据 CPU 核心数调整(如 CPU 核心数的 2 倍)。掌握 Qt 多线程技术,能让你轻松应对复杂的并发场景,开发出高效、流畅的跨平台应用。建议多动手实践,结合实际项目场景灵活运用不同的同步机制和线程管理方式。如果你有任何问题或需要进一步探讨高级场景,欢迎在评论区留言交流!