QThread 用法探究一:
QT使用moveThread开启多线程:
1.创建一个基于QObejct 的类 Controller(在此类中创建多线程的类,并启动多线程)
2.创建一个基于QObject 的类Worker; (运行在单独的线程中)
3.在Worker类中,创建一个槽函数doWorker(); 用于运行多线程里面的代码,所有耗时的代码全部在这个槽函数里面运行。
4.在Controller里面将Worker 的实例调用moveToThread(QThread *thread),并连接信号槽。并start()启动线程。(为什么使用信号槽调用呢?为什么不可以直接m_worker->signalCall()呢?)
m_worker = new Worker();
m_worker->moveToThread(&m_thread);
connect(&m_thread, &QThread::started, m_worker, &Worker::signalCall);//多线程开始工作
connect(&m_thread, &QThread::finished, m_worker, &Worker::deleteLater);//
connect(m_worker, &Worker::finished, this, &Controller::stopWork);//线程类结束后,通知删除
m_thread.start(); //线程开始
5.在Controller的析构函数里调用:
Controller::~Controller()
{
stopWork();
}
void Controller::stopWork()
{
if (m_worker != Q_NULLPTR) {
m_worker->deleteLater();
m_worker = Q_NULLPTR;
}
if (m_thread.isRunning()) {
m_thread.quit();
m_thread.wait();
}
}
Controller:
Controller::Controller(QObject *parent) : QObject(parent)
{
m_worker = new Worker();
m_worker->moveToThread(&m_thread);
connect(&m_thread, &QThread::started, m_worker, &Worker::signalCall);
connect(&m_thread, &QThread::finished, m_worker, &Worker::deleteLater);
connect(m_worker, &Worker::finished, this, &Controller::stopWork);
qDebug() << "main controller thread id = "<< QThread::currentThreadId();
m_worker->directCall();//验证为什么不能直接调用函数,而是通过信号槽进行调用
m_thread.start();
}
Controller::~Controller()
{
stopWork();
}
void Controller::stopWork()
{
if (m_worker != Q_NULLPTR) {
m_worker->deleteLater();
m_worker = Q_NULLPTR;
}
if (m_thread.isRunning()) {
m_thread.quit();
m_thread.wait();
}
}
Worker类:
Worker::Worker(QObject *parent)
{
}
Worker::~Worker()
{
}
void Worker::directCall()
{
qDebug() << "direct call thread id = " << QThread::currentThreadId();
}
void Worker::signalCall()
{
qDebug() << "signal slot call thread id = " << QThread::currentThreadId();
}
我们在Worker类中有两个函数,directCall与signalCall两个函数,分别是对Worker类的实例直接调用与通过信号槽调用,看看有什么不同。
result:
main controller thread id = 0x426c //主线程id
direct call thread id = 0x426c //直接调用,发生在的线程
signal slot call thread id = 0x3814 //通过信号槽调用,发生的线程
通过结果,我们可以看到:
主线程的线程id为0x426c
通过直接调用,函数执行在线程0x426c
通过信号槽调用,函数执行再线程0x3814
可以看到,如果通过直接调用的话, 还是会在主线程中执行函数,与普通的函数调用相同。
如果通过信号槽调用,则是在多线程中执行。这才是达到我们的目的。
结论:
通过moveToThread运用新线程中,需要通过信号槽、事件等才能在多线程中执行。如果通过直接调用的话,则还是在主线程中执行。