wxWidgets第十四課 wxTimer定時器

說明

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


問題

    比如定時器函數運行耗時10秒,定時的時間是10毫秒,是否是每隔10毫秒執行一次定時器函數,還是等待定時器函數運行結束,纔開始重新計時


結果

    在定時器函數中執行::Sleep(10000);等待10秒,發現實際上需要等待定時器函數執行結束,纔開始重新計時。所以在如下的場景需要特別小心:需要定時讀取數據,而讀取數據之後,執行一大堆耗時的操作,這個時候,就需要啓動線程去處理,而不能在定時器函數中完成


例子

#include "wx/timer.h"


private:

wxTimer *m_timer;


//指定定時器的ID

#define TIMER_ID 1000

//將定時器ID和定時執行函數關聯起來

EVT_TIMER(TIMER_ID, CFlightInstrumentPanel::OnTimer)


//創建定時器,指定定時器ID使用哪個定時器

m_timer = new wxTimer(this, TIMER_ID);

//啓動定時器,參數是定時的時間間隔

m_timer->Start(1000);


編寫定時器的執行內容

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();


注意

定時器是一種資源,類似文件句柄,不可能無限的創建,定時結束之後,最後停止定時器,釋放資源,並且如果在關閉窗口之前沒有停止定時器,會出現


0xC0000005: 讀取位置 0xFEEEFF06 時發生訪問衝突錯誤,相關的內容查看其它的文章





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

    項目中使用wxWidgets框架,其中應用了該框架的定時器wxTimer,頻繁進行了開啓和關閉。在嵌入式操作系統中,性能是重中之重因此想嘗試分析當前這種應用場景,是否會消耗CPU和內存的資源,跟蹤wxWidgets的源碼,發現定時器在windows系統下調用了使用了SetTimer和KillTimer函數進行定時器的啓動和銷燬。


疑惑

第一點:啓動定時器是否是啓動一條線程,然後Sleep等待時間的觸發

第二點:頻繁啓動定時器,然後關閉,是否需消耗大量的資源

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

可觀的開銷


解惑

第一點:啓動定時器SetTimer不是啓動一個線程。該函數主要將新的

定時器結構加入內核的全局變量gptmrFirst這個鏈表,使用

KillTimer移除該定時器的結構體。系統會定時遍歷該鏈表,

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

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

第二點:啓動和關閉定時器也只是添加或者移除結構體,效率應該是

比較高的。創建線程的開銷以及佔用的堆棧都是可觀的,儘管

可以設置線程堆棧的大小



前提

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


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


基於以下的論斷:

win32k中有一個全局變量gptmrFirst,裏面存放了第一個定時器結構的指針,定時器結構以鏈表的形式儲存

線程在消息循環中會調用GetMessageW->NtUserGetMessage->xxxInternalGetMessage->xxxRealInternalGetMessage

xxxRealInternalGetMessage後面會調用DoTimer,DoTimer就遍歷整個定時器鏈表,並比較每個Timer的Win32Thread指針是不是於win32k的


全局變量gptiCurrent,gptiCurrent中保存的是當前線程的Win32Thread結構的指針(許多win32k函數開頭都會有EnterCrit,這裏面就設


置gptiCurrent爲PsGetThreadWin32Thread的返回值)

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


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


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

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


器,如果主定時器到時,就執行TimerProc

TimerProc函數會遍歷gptmrFirst鏈表,減少每個定時器的剩餘時間,並把到期的定時器設置爲已就緒


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章