美文网首页
QTimer在QThread中失效

QTimer在QThread中失效

作者: NullUser | 来源:发表于2021-08-01 23:25 被阅读0次

    通过继承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正常工作。

    相关文章

      网友评论

          本文标题:QTimer在QThread中失效

          本文链接:https://www.haomeiwen.com/subject/mjxdvltx.html