通过继承QThread类重写run函数实现多线程时,在run()中开启QTimer,并连接timeout信号,会发现无法收到timeout信号,从而导致无法执行槽函数。
根据QT对QTimer的官方介绍:
In multithreaded applications, you can use “QTimer” in any thread that has an event loop. To start an event loop from a non-GUI thread, use “QThread::exec()”. Qt uses the timer's “thread affinity” to determine which thread will emit the “timeout()” signal. Because of this, you must start and stop the timer in its thread; it is not possible to start a timer from another thread.
QTimer是基于事件循环的,如果自定义线程中没有开启事件循环,那么QTimer相应的也不会起作用。QThread提供了exec()函数,可以开启事件循环,从而可以正常使用QTimer。
测试demo如下:
MyTimer类
mytimer.h
#ifndef MYTIMER_H
#define MYTIMER_H
#include <QObject>
#include <QMutex>
class QTimer;
class MyTimer:public QObject
{
Q_OBJECT
public:
static MyTimer* getInstance();
private:
MyTimer();
private slots:
void slotTest();
private:
QTimer *m_timer;
static MyTimer *ins;
static QMutex mute;
};
#endif // MYTIMER_H
mytimer.cpp
#include "mytimer.h"
#include <QTimer>
#include <QDebug>
MyTimer *MyTimer::ins = nullptr;
QMutex MyTimer::mute;
MyTimer::MyTimer():
m_timer(new QTimer(this))
{
connect(m_timer, SIGNAL(timeout()), this, SLOT(slotTest()));
m_timer->start(1000);
}
MyTimer* MyTimer::getInstance()
{
if(ins == nullptr)
{
mute.lock();
if(ins == nullptr)
{
ins = new MyTimer();
}
mute.unlock();
}
return ins;
}
void MyTimer::slotTest()
{
qDebug()<<"test";
}
MyThread类
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include "mytimer.h"
class MyThread : public QThread
{
public:
MyThread();
void run() override
{
MyTimer::getInstance();
//开启事件循环
exec();
}
};
#endif // MYTHREAD_H
MyTimer使用单例模式,在构造对象时,实例化QTimer,并通过QTimer每秒打印一个test。如果我们首先在MyThread线程中调用MyTimer::getInstance(),那么该单例对象在MyThread中构造,从而QTimer是在MyThread中创建的,如果在run()函数中没有执行exec(),那么就没有开启事件循环,导致QTimer的定时任务不起作用。当我们在run()中执行exec()后,该线程拥有event loop,便可确保QTimer正常工作。
网友评论