线程创建
自定义线程类
cpp
#ifndef CUSTOMETHREAD_H
#define CUSTOMETHREAD_H
#include <QObject>
#include <QThread>
#include "add.h"
class CustomeThread : public QThread
{
Q_OBJECT
public:
// Bind the thread kernel function.
explicit CustomeThread(Add*& addPtr);
private:
// Run the thread kernel function
virtual void run() override;
private:
Add* m_addFuc {nullptr};
};
#endif // CUSTOMETHREAD_H
主函数
cpp
#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include "add.h"
#include "customethread.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Current thread id: " << QThread::currentThreadId();
//Concrator the thread kernel function object.
Add* ladd = new Add();
CustomeThread* thread = new CustomeThread(ladd);
thread->start();
return a.exec();
}
结果:
shell
Current thread id: 0x36d0
current Thread: 0x7f50
100 + 200 = 300
计算的核心函数在子线程中进行。
通过创建一个线程的controller 类,绑定线程执行的kernel函数。然后再子线程的run函数里执行 kernel 函数。
改进
上面的程序中 kernel 函数和 执行线程并没有在同一个线程下,所以虽然Qt通过跨线程调用的机制,在子线程调用成功了,但是终究是一种不安全的方式,所以,为了保险起见,需要将 kernel函数再移入子线程。
cpp
#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include "add.h"
#include "customethread.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Current thread id: " << QThread::currentThreadId();
//Concrator the thread kernel function object.
Add* ladd = new Add();
CustomeThread* thread = new CustomeThread(ladd);
ladd->moveToThread(thread);
thread->start();
return a.exec();
}
线程循环
事件循环
cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
return a.exec();
}
上面的 a.exec() 即让程序进入系统的事件循环,事件循环是一个特殊的死循环,其作用如下:
- 阻塞程序,使得线程一直执行。
- 在循环内部可以不断的监听系统发来的信号,并作出反应。
cpp
#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>
#include <QObject>
#include "add.h"
#include "customethread.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Current thread id: " << QThread::currentThreadId();
Add* ladd = new Add();
CustomeThread* thread = new CustomeThread(ladd);
ladd->moveToThread(thread);
thread->start();
QTimer* timer = new QTimer();
QObject::connect(timer, SIGNAL(timeout()), ladd, SLOT(add()));
return a.exec();
}
在这个例子里面,使用了一个定时器,向子线程里的 kernel 对象发送信号,出发 add() 槽函数。但是最后并没有触发到。一个原因是: 此时的 ladd 已经在子线程了, 直接连接信号槽,大部分时候只能在信号和槽函数在同一个线程时生效。比如,我们不把 ladd移动到子线程中:
cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Current thread id: " << QThread::currentThreadId();
Add* ladd = new Add();
CustomeThread* thread = new CustomeThread(ladd);
// Not move ladd to subthread!!!!
//ladd->moveToThread(thread);
thread->start();
QTimer* timer = new QTimer();
QObject::connect(timer, SIGNAL(timeout()), ladd, SLOT(add()));
return a.exec();
}
shell
Main thread id: 0x5628
Current Thread: 0x5628
100 + 100 = 200
Current Thread: 0x5628
100 + 100 = 200
Current Thread: 0x5628
100 + 100 = 200
Current Thread: 0x5628
100 + 100 = 200
Current Thread: 0x5628
100 + 100 = 200
如何子线程的对象发信号?
可以这样连接信号和操
cpp
QObject::connect(timer, SIGNAL(timeout()), ladd, SLOT(add()), Qt::QueuedConnection);
向子线程发了信号,子线程就能接受吗?
但是发现即时这样也不能向子线程发信号,这是因为子线程中的run函数并没有调用事件循环,此时子线程已经结束退出了,所以可以在子线程的run函数中增加事件循环
cpp
void CustomeThread::run()
{
exec();
}
shell
Main thread id: 0x5384
Current Thread: 0x1638
100 + 100 = 200
Current Thread: 0x1638