如何正确使用QThread

简介: 简述要实现一个线程很简单,写一个函数,绑定一些数据,如果有必要的话,可以使用 mutex 或者其他方法来保证和线程的安全交互。无论是 Win32、POSIX 或其他线程,工作原理都基本相同,并相当可靠。至少我敢说比 socket 更容易使用和处理。简述worker-objectworker-object使用 QThread 时,最主

简述

要实现一个线程很简单,写一个函数,绑定一些数据,如果有必要的话,可以使用 mutex 或者其他方法来保证和线程的安全交互。

无论是 Win32、POSIX 或其他线程,工作原理都基本相同,并相当可靠。至少我敢说比 socket 更容易使用和处理。

worker-object

使用 QThread 时,最主要的事情是把它当成一个线程对象的封装。此封装提供了信号、槽和方法,可以轻松地使用 Qt 项目中的线程对象。这说明了子类化 QThread 并实现其 run() 函数是非常错误的。

一个 QThread 应该更像一个普通线程实例:准备一个 QObject 类和所有想要的功能,然后创建一个新的QThread,使用 moveToThread(QThread *) 将 QObject 对象移动至线程中,并调用 QThread 实例的 start() 函数。就这样,再设置适当的信号/槽连接使它正常退出,所有的事情就都做完了。

实现一个简单的 Worker 类:

class Worker : public QObject {
    Q_OBJECT

public:
    Worker();
    ~Worker();

public slots:
    void process();

signals:
    void finished();
    void error(QString err);

private:
    // 在此处添加变量
};

至少需要添加一个共有的槽函数,用于触发实例,一旦线程开启,就立刻处理数据。

现在,看看这个类的基本实现:

Worker::Worker() {
    // 这里,可以从构造函数参数拷贝数据到内部变量
}

Worker::~Worker() {
    // 释放资源
}

// 开始处理数据
void Worker::process() {
    // 这里,使用新分配资源
    qDebug("Hello World!");
    emit finished();
}

虽然 Worker 类没有做什么特别的事情,但它包含了所有必需的元素。当其主函数(这种情况下,是 process())被调用,就立即开始处理数据。当处理完成以后,会发射 finished() 信号,将被用来触发 QThread 实例的退出。

顺便说一句,这里需要注意的一个极为重要的事情 - 永远不应该在 QObject 类的构造函数中使用堆对象(new)。因为分配之后,会在主线程上执行,而非 QThread 实例。这意味着新创建的对象由主线程所拥有,而非 QThread 实例,这将使你的代码无法正常工作。相反,在这种情况下,在主函数(process())中分配这些资源,当被调用时,对象将会在新线程实例中。因此,它将拥有资源。

现在,来看看如何通过创建一个新的 Worker 实例,并把它放在一个 QThread 实例中:

QThread *thread = new QThread();
Worker *worker = new Worker();
worker->moveToThread(thread);

// 错误处理
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));

// 处理数据
connect(thread, SIGNAL(started()), worker, SLOT(process()));

// 退出、删除
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

// 启动线程
thread->start();

注意: connect() 系列是最为关键的部分。

当 worker 实例发出 finished() 信号时,线程就会退出。然后,使用相同的信号用于删除 worker。

为了防止讨厌的 crash(有可能当 thread 被删除时,还没有完全关闭),连接 thread(非 worker)的 finished() 信号到其自身的 deleteLater() 槽函数。这时,只有线程在完全退出时,才会被删除。

目录
相关文章
|
4月前
|
人工智能
Qt主线程
【8月更文挑战第3天】Qt主线程。
57 10
|
7月前
|
消息中间件 Java Android开发
Handler HandlerThread 以及Thread
Handler HandlerThread 以及Thread
39 1
|
7月前
|
Java API C++
【C++ 与Qt 线程】C++ std::thread 与Qt qthread多线程混合编程
【C++ 与Qt 线程】C++ std::thread 与Qt qthread多线程混合编程
286 1
|
7月前
|
存储 安全 程序员
深入理解Qt多线程编程:QThread、QTimer与QAudioOutput的内在联系__Qt 事件循环(二)
深入理解Qt多线程编程:QThread、QTimer与QAudioOutput的内在联系__Qt 事件循环
896 0
|
7月前
|
安全 测试技术 C++
深入理解Qt多线程编程:QThread、QTimer与QAudioOutput的内在联系__Qt 事件循环(一)
深入理解Qt多线程编程:QThread、QTimer与QAudioOutput的内在联系__Qt 事件循环
489 0
|
7月前
|
安全
深入理解Qt多线程编程:QThread、QTimer与QAudioOutput的内在联系__Qt 事件循环(三)
深入理解Qt多线程编程:QThread、QTimer与QAudioOutput的内在联系__Qt 事件循环
222 0
|
安全 Java 调度
Java多线程01—线程的初步理解和基于Thread类创建线程
Java多线程01—线程的初步理解和基于Thread类创建线程
138 0
创建线程
创建线程
132 0
创建线程
|
安全
Qt跨线程的信号和槽的使用
Qt跨线程的信号和槽的使用
547 0