您好,登錄后才能下訂單哦!
說明
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鏈表,減少每個定時器的剩余時間,并把到期的定時器設置為已就緒
免責聲明:本站發(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)容。