久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

在不開(kāi)啟事件循環(huán)的線程中使用QTimer | 求索閣

 guitarhua 2016-09-07

QTimer是Qt自帶的定時(shí)器類(lèi),,QTimer運(yùn)行時(shí)是依賴(lài)于事件循環(huán)的,簡(jiǎn)單來(lái)說(shuō),,在一個(gè)不開(kāi)啟事件循環(huán)(未調(diào)用exec() )的線程中,,QTimer是無(wú)法使用的。通過(guò)分析Qt源碼可發(fā)現(xiàn),,調(diào)用QTimer::start()后僅僅是在系統(tǒng)的定時(shí)器向量表中添加了一個(gè)定時(shí)器對(duì)象,,但定時(shí)器并沒(méi)有真正開(kāi)啟。定時(shí)器的開(kāi)啟需要通過(guò)processEvent()開(kāi)始的一系列調(diào)用后才會(huì)真正得開(kāi)啟,,這個(gè)過(guò)程中會(huì)處理定時(shí)器向量表中所有的定時(shí)器對(duì)象,。那么實(shí)際exec()中也是在不斷地調(diào)用processEvent()方法,。

問(wèn)題

在項(xiàng)目中可能會(huì)遇到某條常駐線程,run()中運(yùn)行著一個(gè)處理事務(wù)的死循環(huán),,在死循環(huán)中若想直接使用QTimer來(lái)實(shí)現(xiàn)定時(shí)功能,,那么是不行的。我自己的的項(xiàng)目中是為了實(shí)現(xiàn)串口讀寫(xiě)的超時(shí)判斷,,所以需要用到定時(shí)器,。

解決

網(wǎng)上可以搜到解決方案,并且很好用,,但是存在問(wèn)題,。先說(shuō)一下思路:

定時(shí)器對(duì)象需要在一個(gè)開(kāi)啟事件循環(huán)的線程中運(yùn)行,那么通過(guò)moveToThread() 方法我們將它移至一個(gè)開(kāi)啟了事件循環(huán)的線程中運(yùn)行就可以了,。很happy,,我們很快的封裝了一個(gè)定時(shí)器類(lèi),包含了一個(gè)QTimer及QThread對(duì)象,,直接使用QThread對(duì)象是因?yàn)槲业腝t版本是4.8.3,,run()不是純虛函數(shù),默認(rèn)開(kāi)啟了事件循環(huán),。主要代碼如下:

#ifndef QCUSTOMTIMER_H 
#define QCUSTOMTIMER_H 
 
#include <QObject> 
#include <QTimer> 
#include <QThread> 
 
class QCustomTimer : public QObject 

    Q_OBJECT 
public: 
    explicit QCustomTimer(QObject *parent = 0); 
    ~QCustomTimer(); 
 
private: 
    QTimer      *m_pTimer;       //定時(shí)器對(duì)象 
    QThread     *m_pTimerThread; //定時(shí)器依賴(lài)線程 
 
signals: 
    void startSignal( int nMsc );//開(kāi)啟定時(shí)器信號(hào) 
    void stopSignal();           //停止定時(shí)器信號(hào) 
    void TimeOut();              //定時(shí)器觸發(fā),,外部需連接此信號(hào) 
    void deletelater();          //延時(shí)刪除定時(shí)器信號(hào) 
public slots: 
    void onTimer();              //對(duì)象內(nèi)部定時(shí)觸發(fā)槽函數(shù),向外部發(fā)射定時(shí)器觸發(fā)信號(hào) 
public: 
    void StartTimer( int nMsc ); //開(kāi)啟定時(shí)器 
    void StopTimer();            //關(guān)閉定時(shí)器 
    void DeleteLater();          //延時(shí)刪除定時(shí)器對(duì)象 
 
}; 
 
#endif // QCUSTOMTIMER_H 

#include "qcustomtimer.h" 
 
QCustomTimer::QCustomTimer(QObject *parent) : 
    QObject(parent) 

    m_pTimer = new QTimer(0); 
    m_pTimer->setSingleShot( true );//單次觸發(fā) 
 
    m_pTimerThread->start(); 
 
    m_pTimer->moveToThread( m_pTimerThread );//更改定時(shí)器運(yùn)行的線程 
 
    connect( m_pTimer, SIGNAL(timeout()), this, SLOT(onTimer()) , Qt::DirectConnection );//定時(shí)器事件觸發(fā)槽 
 
    connect( this, SIGNAL(startSignal(int)), m_pTimer, SLOT(start( int ) ), Qt::BlockingQueuedConnection );//連接定時(shí)器啟動(dòng)槽函數(shù),,不可用“直連” 
 
    connect( this, SIGNAL(stopSignal()), m_pTimer, SLOT(stop()), Qt::BlockingQueuedConnection );//連接定時(shí)器關(guān)閉槽函數(shù),,不可用“直連” 
 
    connect( this, SIGNAL( deletelater() ), m_pTimer, SLOT(deleteLater()) );//刪除位于線程中的定時(shí)器對(duì)象,插入一個(gè)延時(shí)刪除的事件 

 
QCustomTimer::~QCustomTimer() 

    StopTimer(); 
    DeleteLater(); 

 
void QCustomTimer::onTimer() 

    emit TimeOut();//發(fā)射定時(shí)器觸發(fā)信號(hào) 

 
void QCustomTimer::StartTimer(int nMsc) 

    emit startSignal(nMsc) ;//向子線程內(nèi)的定時(shí)器發(fā)送開(kāi)啟定時(shí)器信號(hào) 

 
void QCustomTimer::StopTimer() 

    emit stopSignal();//向子線程內(nèi)的定時(shí)器發(fā)送停止定時(shí)器信號(hào) 

 
void QCustomTimer::DeleteLater() 

    emit deletelater();//向子線程的事件循環(huán)插入一個(gè)延期刪除事件 

實(shí)際在初步使用時(shí),,毫無(wú)問(wèn)題,,定時(shí)器正常觸發(fā)。但是當(dāng)非常頻繁得創(chuàng)建及析構(gòu)QCustomTimer對(duì)象時(shí),,則會(huì)出現(xiàn)崩潰等問(wèn)題,。比較慚愧,此問(wèn)題困擾我很久,,雖然最后解決了問(wèn)題,,但我仍然不知道是什么原因?qū)е拢粲写笈V?,?qǐng)您一定要告訴我?。?/p>

下面說(shuō)說(shuō)上述的代碼:

1. 調(diào)用moveToThread()方法后,,定時(shí)器對(duì)象就屬于子線程的了,,那么要釋放的話(huà),按照文檔來(lái)說(shuō)要么是插入deleteLater()延時(shí)刪除事件,,要么是等run()函數(shù)返回前會(huì)將對(duì)象釋放掉,。上述代碼中使用的是指針,,不使用指針而使用成員變量的形式,我也嘗試過(guò),,程序仍然會(huì)崩潰,。

2. 多說(shuō)一點(diǎn),就是程序崩潰基本要幾個(gè)小時(shí)才會(huì)崩,,程序報(bào)錯(cuò) “純虛函數(shù)被調(diào)用”,,針對(duì)這個(gè)線索google了很多資料,但是沒(méi)有找到應(yīng)對(duì)方案,。

3. 猜測(cè)還是在高頻使用的情況下,,定時(shí)器對(duì)象及線程對(duì)象的析構(gòu)出現(xiàn)了問(wèn)題, 且deleteLater()無(wú)法解決。

我的解決方法,,其實(shí)也不嚴(yán)謹(jǐn),,因?yàn)槲也](méi)有精確定位到BUG。我是將線程對(duì)象改為靜態(tài)的,,即去除了線程對(duì)象的析構(gòu),,只需要正確析構(gòu)掉定時(shí)器對(duì)象,這是deleteLater()就有了效果,。代碼如下:

#ifndef QCUSTOMTIMER_H 
#define QCUSTOMTIMER_H 
 
#include <QObject> 
#include <QTimer> 
#include <QThread> 
 
class QCustomTimer : public QObject 

    Q_OBJECT 
public: 
    explicit QCustomTimer(QObject *parent = 0); 
    ~QCustomTimer(); 
 
private: 
    static QThread     *m_pTimerThread; //定時(shí)器依賴(lài)線程 
    QTimer             *m_pTimer;       //定時(shí)器對(duì)象 
 
signals: 
    void startSignal( int nMsc );//開(kāi)啟定時(shí)器信號(hào) 
    void stopSignal();           //停止定時(shí)器信號(hào) 
    void TimeOut();              //定時(shí)器觸發(fā),,外部需連接此信號(hào) 
    void deletelater();          //延時(shí)刪除定時(shí)器信號(hào) 
public slots: 
    void onTimer();              //對(duì)象內(nèi)部定時(shí)觸發(fā)槽函數(shù),向外部發(fā)射定時(shí)器觸發(fā)信號(hào) 
public: 
    void StartTimer( int nMsc ); //開(kāi)啟定時(shí)器 
    void StopTimer();            //關(guān)閉定時(shí)器 
    void DeleteLater();          //延時(shí)刪除定時(shí)器對(duì)象 
 
}; 
 
#endif // QCUSTOMTIMER_H
 

#include "qcustomtimer.h" 
 
//靜態(tài)線程成員指針初始化 
QThread* QCustomTimer::m_pTimerThread = NULL; 
 
QCustomTimer::QCustomTimer(QObject *parent) : 
    QObject(parent) 

    if ( m_pTimerThread == NULL ) 
    { 
        //此判斷分支依賴(lài)于Qt將靜態(tài)成員指針變量初始化為NULL,,不是好的做法 
        //但如果工程中存在其他全局變量并且有了依賴(lài)關(guān)系,,那么應(yīng)該也就只能這樣了 
        //保證QCustomTimer類(lèi)不要跟其他全局變量產(chǎn)生依賴(lài)關(guān)系,可以在類(lèi)外初始化,,這樣更好 
        m_pTimerThread = new QThread; 
    } 
 
    m_pTimer = new QTimer(0); 
    m_pTimer->setSingleShot( true );//單次觸發(fā) 
 
    m_pTimerThread->start(); 
 
    m_pTimer->moveToThread( m_pTimerThread );//更改定時(shí)器運(yùn)行的線程 
 
    connect( m_pTimer, SIGNAL(timeout()), this, SLOT(onTimer()) , Qt::DirectConnection );//定時(shí)器事件觸發(fā)槽 
 
    connect( this, SIGNAL(startSignal(int)), m_pTimer, SLOT(start( int ) ), Qt::BlockingQueuedConnection );//連接定時(shí)器啟動(dòng)槽函數(shù),,不可用“直連” 
 
    connect( this, SIGNAL(stopSignal()), m_pTimer, SLOT(stop()), Qt::BlockingQueuedConnection );//連接定時(shí)器關(guān)閉槽函數(shù),不可用“直連” 
 
    connect( this, SIGNAL( deletelater() ), m_pTimer, SLOT(deleteLater()) );//刪除位于線程中的定時(shí)器對(duì)象,,插入一個(gè)延時(shí)刪除的事件 

 
QCustomTimer::~QCustomTimer() 

    StopTimer(); 
    DeleteLater(); 

 
void QCustomTimer::onTimer() 

    emit TimeOut();//發(fā)射定時(shí)器觸發(fā)信號(hào) 

 
void QCustomTimer::StartTimer(int nMsc) 

    emit startSignal(nMsc) ;//向子線程內(nèi)的定時(shí)器發(fā)送開(kāi)啟定時(shí)器信號(hào) 

 
void QCustomTimer::StopTimer() 

    emit stopSignal();//向子線程內(nèi)的定時(shí)器發(fā)送停止定時(shí)器信號(hào) 

 
void QCustomTimer::DeleteLater() 

    emit deletelater();//向子線程的事件循環(huán)插入一個(gè)延期刪除事件 

需要說(shuō)明的就是靜態(tài)線程的初始化位置,,我的做法是個(gè)權(quán)宜之計(jì),因工程中其他全局變量與定時(shí)器類(lèi)產(chǎn)生了依賴(lài)關(guān)系,,導(dǎo)致只能這樣做,。關(guān)于設(shè)計(jì)模式還是需要好好學(xué)習(xí),避免這些糟糕的設(shè)計(jì),。
上述就是完整的代碼,,如果有bug或者問(wèn)題,歡迎給我留言?。?/p>

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶(hù)發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多