醋醋百科网

Good Luck To You!

Qt线程使用中容易踩的雷_qt5多线程waitquit

一 正确运用:Worker对象模式

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QTimer>
// 1. 创建Worker对象(实际业务逻辑)
class Worker : public QObject {
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr) : QObject(parent) {}
public slots:
void processTask() {
qDebug() << "工作线程:" << QThread::currentThread();
// 模拟耗时操作
QThread::sleep(2);
emit resultReady(42);
}
signals:
void resultReady(int value);
};
// 2. 线程控制器(管理线程生命周期)
class ThreadController : public QObject {
Q_OBJECT
public:
explicit ThreadController(QObject *parent = nullptr)
: QObject(parent), worker(new Worker), thread(new QThread(this))
{
// 将worker移动到新线程
worker->moveToThread(thread);
// 连接线程信号
connect(thread, &QThread::started, worker, &Worker::processTask);
connect(worker, &Worker::resultReady, this, &
ThreadController::handleResult);

connect(thread, &QThread::finished, worker, &QObject::deleteLater);
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
}
void start() {
thread->start();
}
void stop() {
thread->quit();
thread->wait(); // 等待线程安全退出
}
signals:
void finalResult(int);
private slots:
void handleResult(int value) {
qDebug() << "处理结果的线程:" << QThread::currentThread();
emit finalResult(value * 2);
}
private:
Worker *worker;
QThread *thread;
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
ThreadController controller;
// 连接最终结果信号
QObject::connect(&controller, &
ThreadController::finalResult, [](int val) {

qDebug() << "最终结果:" << val << "来自线程:" << QThread::currentThread();
});
// 启动线程任务
controller.start();
// 安全停止示例(5秒后停止)
QTimer::singleShot(5000, [&]{
controller.stop();
app.quit();
});
return app.exec();
}
#include "main.moc"



二 正确运用:QThread子类添加信号

class SafeThread : public QThread {
Q_OBJECT
public:
explicit SafeThread(QObject *parent = nullptr) : QThread(parent) {}
signals: // 线程安全:可以添加信号
void progressUpdated(int percent);
void calculationComplete(double result);
protected:
void run() override {
for (int i = 0; i <= 100; ++i) {
QThread::msleep(50);
emit progressUpdated(i); // 安全发射信号
}
emit calculationComplete(3.14159);
}
};
// 使用示例
SafeThread thread;
QObject::connect(&thread, &
SafeThread::progressUpdated, [](int val) {

qDebug() << "进度:" << val << "%";
});
thread.start();



三 禁止操作示例

// 危险示例1:在QThread子类添加槽函数
class BadThread : public QThread {
Q_OBJECT
public slots: // 危险!
void dangerousSlot() {
// 此槽在主线程执行,而非工作线程!
qDebug() << "当前线程:" << QThread::currentThread();
}
};
// 危险示例2:错误使用moveToThread
void run() {
this->moveToThread(this); // 导致未定义行为
// ...
}
// 危险示例3:强制终止线程
thread.terminate(); // 可能导致资源泄漏
// 危险示例4:提前销毁线程对象
QThread* thread = new QThread;
Worker* worker = new Worker;
worker->moveToThread(thread);
thread->start();
// 错误:线程仍在运行时销毁对象
delete thread;
delete worker;
// 正确做法:安全退出线程
thread->quit();
thread->wait(); // 等待线程结束
delete worker;
delete thread;


四 何时应该使用线程?

  1. 阻塞API调用场景

// 模拟阻塞API调用
void blockingAPICall() {
// 传统同步API(无回调机制)
qDebug() << "调用阻塞API...";
QThread::sleep(3); // 模拟阻塞操作
}
// 主线程中调用会导致界面冻结
// 解决方案:移至工作线程
QThread* thread = QThread::create([]{
blockingAPICall();
});
thread->start();

  1. CPU密集型计算

// 计算斐波那契数列(CPU密集型)
long fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
// 在工作线程执行
QThread::create([]{
auto result = fibonacci(45);
qDebug() << "计算结果:" << result;
})->start();

  1. 第三方同步库集成

// 第三方同步库接口
extern "C" void sync_library_process(); // 阻塞调用
// 封装到线程
QThread::create([]{
sync_library_process();
})->start();


五 最佳实践总结

  1. 架构设计原则
  2. 使用Worker对象模式分离业务逻辑与线程控制
  3. 保持QThread子类简单(仅重写run()方法)
  4. 通过信号进行线程间通信
  5. 生命周期管理

// 安全线程退出流程
thread->quit(); // 请求退出
thread->wait(); // 等待结束
worker->deleteLater(); // 安全删除

  1. 错误处理

// 连接线程错误信号
connect(thread, &QThread::finished, [&] {
if (thread->isFinished()) {
qDebug() << "线程正常退出";
}
});
// 处理未捕获异常
connect(thread, &QThread::errorOccurred, [](QThread::Error error) {
qCritical() << "线程错误:" << error;
});

  1. 资源优化

// 使用线程池(QtConcurrent)
QtConcurrent::run([]{
// 自动复用线程资源
cpuIntensiveTask();
});

遵循这些实践原则,您可以安全高效地在Qt应用中使用多线程,同时避免常见的并发编程陷阱。记住:线程是强大的工具,但应该仅在必要时使用,并始终优先考虑异步和非阻塞解决方案。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言