QTimer使用问题

1. 概述

QT中使用定时器QTimer时,一不小心可能就会造成定时器失效的情况,这个问题的本质是QTimer实例运行在了一个没有启用事件循环的线程中,从而造成其失效

2. 使用场景

  • 主线程中使用
  • 子线程中使用

2.1 注意

定时器的创建与使用要在同一个线程中,这个问题的演示会在2.2.2 QThread小节中进行

2.2 主线程中使用

  1. 首先创建一个QTimerInMainThread类,内容如下:
    #ifndef QTIMERRUNINTHREAD_H
    #define QTIMERRUNINTHREAD_H
    
    #include <QObject>
    #include <QTimer>
    
    class QTimerInMainThread : public QObject
    {
        Q_OBJECT
    public:
    
        QTimerInMainThread();
        ~QTimerInMainThread();
    
        QTimer m_timer;
        int m_count;
    public slots:
        void timeoutHandle();
    
    };
    
    #endif // QTIMERRUNINTHREAD_H
    
  2. 实现QTimerInMainThread
    #include "QTimerRunInThread.h"
    #include <QThread>
    #include <QDebug>
    
    QTimerInMainThread::QTimerInMainThread()
        : m_count(0)
    {
    
        QObject::connect(&m_timer,&QTimer::timeout,this,&QTimerInMainThread::timeoutHandle);
        m_timer.start(100);
    }
    
    QTimerInMainThread::~QTimerInMainThread()
    {
        m_timer.stop();
    }
    
    void QTimerInMainThread::timeoutHandle()
    {
        qDebug() << "current thread id: " <<  QThread::currentThreadId() << "m_count: " << m_count++;
    }
    
    
  3. main.cpp
#include <QCoreApplication>
#include "QTimerObjectInQThread.h"
#include <QDebug>
#include <QThread>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug() << "main thread id: " <<  QThread::currentThreadId() ;
    /*
     * 第一种方式:定时器运行在主线程中
     *  直接主线程中启动一个定时器
    */
    static QTimerInMainThread mainThreadTimer;
    return a.exec();
}

2.3 子线程中使用

QT中线程的使用通常分为两种,接下来就以这两种进行举例。

2.3.1 moveToThread

  1. 创建QTimerMoveToChildrenThread
    #ifndef QTIMERMOVETOCHILDRENTHREAD_H
    #define QTIMERMOVETOCHILDRENTHREAD_H
    
    #include <QObject>
    #include <QTimer>
    #include <QThread>
    
    class QTimerMoveToChildrenThread: public QObject
    {
        Q_OBJECT
    public:
        QTimerMoveToChildrenThread();
        ~QTimerMoveToChildrenThread();
    
        void start();
        void stop();
    
        QTimer m_timer;
        QThread m_timerThread;
        int m_count;
    
    signals:
        void startSignal(int msec);
        void stopSignal();
    
    public slots:
        void timeoutHandle();
    };
    
    #endif // QTIMERMOVETOCHILDRENTHREAD_H
    
    
  2. 实现QTimerMoveToChildrenThread
    #include "QTimerMoveToChildrenThread.h"
    #include <QDebug>
    
    QTimerMoveToChildrenThread::QTimerMoveToChildrenThread()
        : m_count(0)
    {
        // 更改定时器运行的线程
        m_timer.moveToThread(&m_timerThread);
    
    
        // 定时器触发事件
        connect(&m_timer,&QTimer::timeout,this,&QTimerMoveToChildrenThread::timeoutHandle);
    
        // 连接定时器启动槽函数
        QObject::connect(this,static_cast<void (QTimerMoveToChildrenThread::*)(int)>(&QTimerMoveToChildrenThread::startSignal),
                         &m_timer,static_cast<void (QTimer::*)(int)>(&QTimer::start));
        // 连接定时器关闭槽函数
        QObject::connect(this,&QTimerMoveToChildrenThread::stopSignal,&m_timer,&QTimer::stop);
    
        m_timerThread.start();
    }
    
    QTimerMoveToChildrenThread::~QTimerMoveToChildrenThread()
    {
        stop();
        m_timerThread.quit();
    }
    
    void QTimerMoveToChildrenThread::start()
    {
        //向子线程内的定时器发送开启定时器信号
        emit startSignal(100);
    }
    
    void QTimerMoveToChildrenThread::stop()
    {
        //向子线程内的定时器发送停止定时器信号
        emit stopSignal();
    }
    
    void QTimerMoveToChildrenThread::timeoutHandle()
    {
        // 这个在主线程中执行
        qDebug() << "current thread id: " <<  QThread::currentThreadId() << "m_count: " << m_count++;
    }
    
  3. main.cpp
    #include <QCoreApplication>
    #include "QTimerMoveToChildrenThread.h"
    #include <QDebug>
    #include <QThread>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        qDebug() << "main thread id: " <<  QThread::currentThreadId() ;
        /*
         * 第二种方式:定时器运行在子线程中
         *  将定时器移动到子线程中,外部发送启动信号启动子线程中的定时器
        */
        static QTimerMoveToChildrenThread moveToChildrenThreadTimer;
        moveToChildrenThreadTimer.start();
        return a.exec();
    }
    

2.3.2 QThread

  1. 创建QTimerObjectInQThread
#ifndef QTIMEROBJECTINQTHREAD_H
#define QTIMEROBJECTINQTHREAD_H

#include <QObject>
#include <QThread>
#include <QTimer>

class QTimerObjectInQThread : public QThread
{
    Q_OBJECT
public:
    QTimerObjectInQThread();
    ~QTimerObjectInQThread();

    QTimer* m_ptimer;
    int m_count;

public slots:
    void timeoutHandle();

protected:
    virtual void run() override;
};

#endif // QTIMEROBJECTINQTHREAD_H

  1. 实现QTimerObjectInQThread
#include "QTimerObjectInQThread.h"
#include <QDebug>

QTimerObjectInQThread::QTimerObjectInQThread()
    : m_count(0)
{

}

QTimerObjectInQThread::~QTimerObjectInQThread()
{
    if(m_ptimer)
    {
        m_ptimer->stop();
        delete m_ptimer;
    }
}

void QTimerObjectInQThread::timeoutHandle()
{
    qDebug() << "current thread id: " <<  QThread::currentThreadId() << "m_count: " << m_count++;
}

void QTimerObjectInQThread::run()
{
    m_ptimer = new QTimer;
    connect(m_ptimer,&QTimer::timeout,this,&QTimerObjectInQThread::timeoutHandle);
    m_ptimer->start(100);
    // 启动事件循环,否则定时器无法生效
    exec();
}

  1. main.cpp
#include <QCoreApplication>
#include "QTimerRunInThread.h"
#include "QTimerMoveToChildrenThread.h"
#include "QTimerObjectInQThread.h"
#include <QDebug>
#include <QThread>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug() << "main thread id: " <<  QThread::currentThreadId() ;
    /*
     * 第二种方式:定时器运行在子线程中
     *  在线程的run()中启动定时器
    */
    QTimerObjectInQThread timerObjectInThread;
    timerObjectInThread.start();
    return a.exec();
}
2.3.2.1 定时器不能在另一个线程启动问题演示
  1. QTimer* m_ptimer;修改为QTimer m_ptimer;
  2. QTimerObjectInQThread类的实现修改如下
    #include "QTimerObjectInQThread.h"
    #include <QDebug>
    
    QTimerObjectInQThread::QTimerObjectInQThread()
        : m_count(0)
    {
    
    }
    
    QTimerObjectInQThread::~QTimerObjectInQThread()
    {
    //    if(m_ptimer)
    //    {
    //        m_ptimer->stop();
    //        delete m_ptimer;
    //    }
    }
    
    void QTimerObjectInQThread::timeoutHandle()
    {
        qDebug() << "current thread id: " <<  QThread::currentThreadId() << "m_count: " << m_count++;
    }
    
    void QTimerObjectInQThread::run()
    {
        //m_ptimer = new QTimer;
        connect(&m_ptimer,&QTimer::timeout,this,&QTimerObjectInQThread::timeoutHandle);
        m_ptimer.start(100);
        // 启动事件循环,否则定时器无法生效
        exec();
    }
    
    
  3. 运行项目会输出以下内容
    QObject::startTimer: Timers cannot be started from another thread
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值