要实现一个线程很简单,写一个函数,绑定一些数据。如果有必要的话,可以使用 mutex 或者其他方法来保证和线程的安全交互。
在 Qt 中,使用线程有几种不同的方式,下面主要演示 QThread + QObject(worker),此方式主要用于涉及事件驱动的编程和跨线程的信号/槽。
| 版权声明:一去、二三里,未经博主允许不得转载。
在使用 worker-object 时,最主要的事情是要记住 QThread 不是一个线程,而是一个线程对象的包装器。这个包装器提供了信号、槽和方法,来轻松地使用 Qt 中的线程对象。
具体的使用,分为以下几步:
QObject::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() {
// 这里,使用 new 分配资源
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()
槽函数。这样以来,只有线程在完全退出时,才会被删除。