溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

wxWidgets第十四課 wxTimer定時器

發(fā)布時間:2020-08-06 12:44:13 來源:網(wǎng)絡 閱讀:4137 作者:fengyuzaitu 欄目:系統(tǒng)運維

說明

    OnIdle CPU空閑的情況下處理消息,如果需要定時功能,就需要使用定時器wxTimer 


問題

    比如定時器函數(shù)運行耗時10秒,定時的時間是10毫秒,是否是每隔10毫秒執(zhí)行一次定時器函數(shù),還是等待定時器函數(shù)運行結(jié)束,才開始重新計時


結(jié)果

    在定時器函數(shù)中執(zhí)行::Sleep(10000);等待10秒,發(fā)現(xiàn)實際上需要等待定時器函數(shù)執(zhí)行結(jié)束,才開始重新計時。所以在如下的場景需要特別小心:需要定時讀取數(shù)據(jù),而讀取數(shù)據(jù)之后,執(zhí)行一大堆耗時的操作,這個時候,就需要啟動線程去處理,而不能在定時器函數(shù)中完成


例子

#include "wx/timer.h"


private:

wxTimer *m_timer;


//指定定時器的ID

#define TIMER_ID 1000

//將定時器ID和定時執(zhí)行函數(shù)關(guān)聯(lián)起來

EVT_TIMER(TIMER_ID, CFlightInstrumentPanel::OnTimer)


//創(chuàng)建定時器,指定定時器ID使用哪個定時器

m_timer = new wxTimer(this, TIMER_ID);

//啟動定時器,參數(shù)是定時的時間間隔

m_timer->Start(1000);


編寫定時器的執(zhí)行內(nèi)容

void CFlightInstrumentPanel::OnTimer( wxTimerEvent& event )

{

static int x = 0;

if (x<1000)

{

wxClientDC dc(this);

wxPen pen(*wxRED,1);

dc.SetPen(pen);

dc.DrawRectangle(x, 0, 200, 300);

dc.SetPen(wxNullPen);

x=x+100;

}

}


停止定時器

m_timer->Stop();


注意

定時器是一種資源,類似文件句柄,不可能無限的創(chuàng)建,定時結(jié)束之后,最后停止定時器,釋放資源,并且如果在關(guān)閉窗口之前沒有停止定時器,會出現(xiàn)


0xC0000005: 讀取位置 0xFEEEFF06 時發(fā)生訪問沖突錯誤,相關(guān)的內(nèi)容查看其它的文章





定時器SetTimer的效率分析場景分析

    項目中使用wxWidgets框架,其中應用了該框架的定時器wxTimer,頻繁進行了開啟和關(guān)閉。在嵌入式操作系統(tǒng)中,性能是重中之重因此想嘗試分析當前這種應用場景,是否會消耗CPU和內(nèi)存的資源,跟蹤wxWidgets的源碼,發(fā)現(xiàn)定時器在windows系統(tǒng)下調(diào)用了使用了SetTimer和KillTimer函數(shù)進行定時器的啟動和銷毀。


疑惑

第一點:啟動定時器是否是啟動一條線程,然后Sleep等待時間的觸發(fā)

第二點:頻繁啟動定時器,然后關(guān)閉,是否需消耗大量的資源

如果第一條成立的話,線程的創(chuàng)建以及切換都是非常

可觀的開銷


解惑

第一點:啟動定時器SetTimer不是啟動一個線程。該函數(shù)主要將新的

定時器結(jié)構(gòu)加入內(nèi)核的全局變量gptmrFirst這個鏈表,使用

KillTimer移除該定時器的結(jié)構(gòu)體。系統(tǒng)會定時遍歷該鏈表,

一旦定時時間就緒,就會向程序發(fā)送WM_TIMER消息,應用程序

接收到消息,開始處理邏輯

第二點:啟動和關(guān)閉定時器也只是添加或者移除結(jié)構(gòu)體,效率應該是

比較高的。創(chuàng)建線程的開銷以及占用的堆棧都是可觀的,盡管

可以設置線程堆棧的大小



前提

當前沒有搜索到windows定時器的源碼


參考:http://bbs.csdn.net/topics/360222963


基于以下的論斷:

win32k中有一個全局變量gptmrFirst,里面存放了第一個定時器結(jié)構(gòu)的指針,定時器結(jié)構(gòu)以鏈表的形式儲存

線程在消息循環(huán)中會調(diào)用GetMessageW->NtUserGetMessage->xxxInternalGetMessage->xxxRealInternalGetMessage

xxxRealInternalGetMessage后面會調(diào)用DoTimer,DoTimer就遍歷整個定時器鏈表,并比較每個Timer的Win32Thread指針是不是于win32k的


全局變量gptiCurrent,gptiCurrent中保存的是當前線程的Win32Thread結(jié)構(gòu)的指針(許多win32k函數(shù)開頭都會有EnterCrit,這里面就設


置gptiCurrent為PsGetThreadWin32Thread的返回值)

如果是,表明這個Timer屬于當前線程,所以就檢查Timer是否已就緒(到時),如果就緒,則調(diào)用StoreQMessage放置一個WM_TIMER或


WM_SYSTIMER消息,后面xxxRealInternalGetMessage會將其取回


csrss.exe進程有一個叫raw input thread的內(nèi)核線程,其內(nèi)核對象地址的地址放在win32k全局變量gptiRit中

這個線程負責處理鍵盤輸入,鼠標輸入等,當然也有定時器,它會使用KeWaitForMultipleObjects等待一組內(nèi)核對象,其中就有主定時


器,如果主定時器到時,就執(zhí)行TimerProc

TimerProc函數(shù)會遍歷gptmrFirst鏈表,減少每個定時器的剩余時間,并把到期的定時器設置為已就緒


向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI