在上一篇文章中,我们介绍了QThread 的用法一,就是通过moveToThread将一个 继承于QObject的对象移到一个新的线程中执行(只能通过信号槽、事件进行调用才会在多线程中运行)详情请见:https://blog.csdn.net/xiezhongyuan07/article/details/86580080
上次我们介绍的那种方法,两个类都是继承于QObject的,那么还有种方法,就是继承于QThread的类,这也是另外一种方法,还上一种还有很多不一样的地方。
1.创建一个基于QObject的类Controller.(在此类中创建多线程的对象,并启动多线程)
2.创建一个基于QThread的类Worker(运行在单独的线程中)
3.在Worker类中,实现虚函数 void run();(所有run函数里的代码,终将在多线程里运行)
protected:
void run();
4.在Controller类里,连接信号槽,然后通过start()启动线程
m_worker = new Worker(this);
connect(m_worker, &Worker::finished, this, &Controller::stopWork);
m_worker->start(); //启动线程(调用run函数在多线程中运行)
这里有个在上篇文章里一样的问题:通过直接调用、信号槽调用、run()函数,这三种情况,都是在主线程执行还是在新建的线程里运行?
这点一定要弄清楚,要不然就是多线程使用的不正确,多线程使用起来,也没什么意义了。
老规矩,我们还是先来做个demo验证一下上面三种调用方式,哪种才会在新建的线程里运行。
Controller类:
Controller::Controller(QObject *parent)
: QObject(parent)
, m_worker(Q_NULLPTR)
{
m_worker = new Worker(this);
qDebug() << "main thread id = "<< QThread::currentThreadId();
connect(this, &Controller::sigCall, m_worker, &Worker::signalCall);
connect(m_worker, &Worker::finished, this, &Controller::stopWork);
m_worker->start(); //启动线程(调用run函数在多线程中运行)
m_worker->directCall(); //直接调用(在主线程中运行)
emit sigCall();
}
Controller::~Controller()
{
stopWork();
}
void Controller::stopWork()
{
qDebug() << "stop work thread id=" << QThread::currentThreadId();
if (m_worker != Q_NULLPTR) {
m_worker->quit();
m_worker->wait();
}
}
Worker类:
Worker::Worker(QObject *parent)
:QThread(parent)
{
}
Worker::~Worker()
{
}
// 调用thread->start() ,后会自动执行run()函数
void Worker::run()
{
qDebug() << "run worker thread id = " << QThread::currentThreadId();
}
// 当做类的普通对象进行调用
void Worker::directCall()
{
qDebug() << "direct call worker thread id = " << QThread::currentThreadId();
}
// 通过信号槽进行调用
void Worker::signalCall()
{
qDebug() << "signal call worker thread id = " << QThread::currentThreadId();
}
那么这样执行的结果是什么呢?
Starting E:\demo\build-threadDemo1-Desktop_Qt_5_7_0_MSVC2013_32bit-Debug\debug\threadDemo1.exe...
main thread id = 0x46a0 //主线程id
direct call worker thread id = 0x46a0 //直接调用 代码运行的线程id
signal call worker thread id = 0x46a0 //信号槽调用 代码运行的线程id
run worker thread id = 0x2b64 //在run函数里代码运行的线程id
stop work thread id= 0x46a0 //
那么结论就出来了,很明显,
通过直接调用, 是运行在主线程里(与moveToThread结果一样)相当于普通的函数调用;
通过信号槽调用, 也是运行在主线程里(与moveToThread的结果不一样);
run()函数里的代码是新的线程里;
所以通过继承于QThread这种方式使用多线程,我们就不能使用信号槽进行调用了,只能是重写void run()函数,所有需要计算或者耗时的代码,都在run函数里进行执行,才是正确的使用方法。