QTimer特点
- 不能跨线程启动和停止定时器。
- 不能在一个线程中启动定时器关联的对象,而在另一个线程释放(析构)此定时器关联的对象。
- 原因:定时器相关的逻辑和数据结构与线程关联,只能在同一个线程中。
- Timer的任务超时,会把定时阻塞。
解决方案1-标准方式
TestTimer2::TestTimer2(QObject *parent)
{
//使用指针变量
m_thread = new QThread(this);
m_timer = new QTimer(0);
m_timer->setInterval(1000);
m_timer->moveToThread(m_thread);
//定时任务放在线程中执行,必须指定参数-Qt::DirectConnection
connect(m_timer, &QTimer::timeout, this, &TestTimer2::updateTimer, Qt::DirectConnection);
void (QTimer::*pStartFun)() = &QTimer::start;
connect(m_thread, &QThread::started, m_timer, pStartFun);
connect(m_thread, &QThread::finished, m_timer, &QTimer::stop);
//启动
m_thread->start();
}
TestTimer2::~TestTimer2()
{
//销毁指针变量-注意先后顺序
if(m_thread){
qInfo()<<"delete thread";
m_thread->quit();
m_thread->wait();
delete m_thread;
m_thread = nullptr;
}
if(m_timer){
qInfo()<<"delete timer";
delete m_timer;
m_timer = nullptr;
}
}
解决方案2-简化版本
TestTimer2::TestTimer2(QObject *parent)
{
//使用指针变量
m_thread = new QThread(this);
m_timer = new QTimer(0);
m_timer->setInterval(1000);
//定时任务放在线程中执行,必须指定参数-Qt::DirectConnection
connect(m_timer, &QTimer::timeout, this, &TestTimer2::updateTimer, Qt::DirectConnection);
connect(m_thread, &QThread::finished, m_timer, &QTimer::stop);
//启动
m_thread->start();
//简化点: 先启动定时器,后移动线程
m_timer->start();
m_timer->moveToThread(m_thread);
}
TestTimer2::~TestTimer2()
{
//销毁指针变量-注意先后顺序
if(m_thread){
qInfo()<<"delete thread";
m_thread->quit();
m_thread->wait();
delete m_thread;
m_thread = nullptr;
}
if(m_timer){
qInfo()<<"delete timer";
delete m_timer;
m_timer = nullptr;
}
}
解决方案3-使用普通变量
TestTimer2::TestTimer2(QObject *parent)
{
//使用普通变量
m_timer.setInterval(1000);
//定时任务放在线程中执行,必须指定参数-Qt::DirectConnection
connect(&m_timer, &QTimer::timeout, this, &TestTimer2::updateTimer, Qt::DirectConnection);
connect(&m_thread, &QThread::finished, &m_timer, &QTimer::stop);
//启动
m_thread.start();
//简化点: 先启动定时器,后移动线程
m_timer.start();
m_timer.moveToThread(&m_thread);
}
TestTimer2::~TestTimer2()
{
m_thread.quit();
m_thread.wait();
}
最后:这样就可以实现定时器在单独的线程中执行,且不会出现跨线程异常。