在Qt中实现多线程主要有两种常用方式:基于QThread的子类化 和QObject+moveToThread的Worker模式。以下是详细说明和示例代码:
1. 传统方法:继承 QThread(适用于简单任务)
cpp
#include <QThread>
#include <QDebug>
class MyThread : public QThread {
Q_OBJECT
protected:
void run() override {
for(int i=0; i<5; i++){
qDebug() << "Thread:" << i;
sleep(1); // 模拟耗时操作
}
}
};
// 使用方式
MyThread thread;
thread.start(); // 启动线程
thread.wait(); // 等待线程结束(可选)
注意:
- 直接在
run()
中编写业务逻辑,但不要在此线程中操作GUI组件。 - Qt4时代的经典方法,Qt5之后推荐Worker模式。
2. 推荐方法:Worker对象 + moveToThread(事件驱动)
cpp
#include <QObject>
#include <QThread>
#include <QDebug>
class Worker : public QObject {
Q_OBJECT
public slots:
void doWork() {
for(int i=0; i<5; i++){
qDebug() << "Worker in thread:" << QThread::currentThreadId();
QThread::sleep(1);
}
emit workFinished();
}
signals:
void workFinished();
};
// 使用方式
QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);
// 连接信号与槽
QObject::connect(thread, &QThread::started, worker, &Worker::doWork);
QObject::connect(worker, &Worker::workFinished, thread, &QThread::quit);
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
QObject::connect(thread, &QThread::finished, worker, &QObject::deleteLater);
thread->start(); // 启动线程事件循环
优势:
- 利用Qt的事件循环,避免阻塞线程。
- 通过信号槽实现线程间通信,天然线程安全。
- 资源管理更清晰,通过
deleteLater
自动释放对象。
3. 线程安全与信号槽
- 跨线程通信:Qt信号槽自动排队(QueuedConnection),无需手动同步。
- 共享数据保护 :使用
QMutexLocker
或QReadWriteLock
保护临界区。
cpp
// 示例:使用QMutex保护共享数据
QString sharedData;
QMutex mutex;
void modifyData() {
QMutexLocker locker(&mutex);
sharedData = "Modified";
}
4. 线程池(QRunnable)
适用于需要频繁创建/销毁线程的场景:
cpp
#include <QRunnable>
#include <QThreadPool>
class Task : public QRunnable {
void run() override {
qDebug() << "Task running in thread pool";
}
};
// 使用方式
Task *task = new Task;
QThreadPool::globalInstance()->start(task);
关键注意事项
- GUI操作限制:所有界面操作必须在主线程完成,通过信号将结果传递回UI线程。
- 事件循环:Worker模式依赖线程的事件循环(默认已启动)。
- 资源释放 :通过
finished
信号触发deleteLater
,避免野指针。 - 避免阻塞:耗时应放在子线程,主线程保持响应。
示例场景:后台计算更新进度
cpp
// Worker类中定义进度信号
signals:
void progressUpdated(int percent);
// UI线程连接信号
QObject::connect(worker, &Worker::progressUpdated,
[](int value){ progressBar->setValue(value); });
通过上述方法,Qt多线程编程既能保持界面流畅,又能高效利用多核CPU资源。