1. 程式人生 > >C++ TIMER與執行緒的關係,以及WM_TIMER訊息的不準確性

C++ TIMER與執行緒的關係,以及WM_TIMER訊息的不準確性

一,SetTimer介紹

SetTimer函式定義如下:

UINT_PTR SetTimer(
HWND hWnd, // 視窗控制代碼
UINT_PTR nIDEvent, // 定時器ID,多個定時器時,可以通過該ID判斷是哪個定時器
UINT nElapse, // 時間間隔,單位為毫秒
TIMERPROC lpTimerFunc // 回撥函式
);

第四個引數如果為NULL,那麼在第一個引數hwnd的視窗過程中處理WM_TIMER訊息來處理定時業務;如果第四個引數不為0,指定為一個函式指標,則直接在該回調函式中處理定時業務。

二,定時器與執行緒的關係

定時器並不是單獨建立了一個執行緒,它存在於建立該定時器的執行緒中,共享同一個棧。定時器只是和執行緒的排程方式不一樣:執行緒開始後,隨時可以掛起,讓其它執行緒執行,等待下次排程,以便繼續執行,因此可以長期執行。 定時器每啟動一次,執行一段程式碼,不可執行長期。長期執行會造成定時器阻塞。執行緒是單獨排程的,定時器只是打斷執行緒的執行,暫時插入執行定時器的程式碼。 簡單來說,就是執行緒在執行過程中,如果到了定時器該執行的時間,那麼該執行緒會被被中斷,插入定時器執行的完整邏輯,定時器邏輯執行完畢,執行緒恢復正常態,繼續執行。

三,WM_TIMER的不準確性

在Windows系統的訊息佇列中,不同的訊息優先順序不同,而WM_TIMER則是優先順序最低的哪一類(同樣的訊息和有WM_PAINT),在GetMessage()時,要等佇列裡沒有其他訊息了才返回它。當佇列裡有其他任何優先順序高的訊息時,會優先處理其他訊息,最後才輪到WM_TIMER,所以WM_TIMER訊息一般都要拖延很長時間才能從佇列裡取出,這就延誤了整理的時機。

四,解決方案

微軟公司在其多媒體Windows中提供了精確定時器的底層API支援。利用多媒體定時器可以很精確地讀出系統的當前時間,並且能在非常精確的時間間隔內完成一個事件、函式或過程的呼叫。利用多媒體定時器的基本功能,可以通過兩種方法實現精確定時。 1)使用timeGetTime()函式,該函式定時精度為ms級,返回從Windows啟動開始所經過的時間。由於使用該函式是通過查詢的方式進行定時控制的,所以,應該建立定時迴圈來進行定時事件的控制。 2)使用timeSetEvent()函式,該函式宣告如下: (在定時器使用完畢後, 應及時呼叫timeKillEvent()將之釋放。)

MMRESULT timeSetEvent( UINT uDelay, 
                                 UINT uResolution, 
                                 LPTIMECALLBACK lpTimeProc, 
                                 WORD dwUser, 
                                 UINT fuEvent )

        uDelay:以毫秒指定事件的週期。
         Uresolution:以毫秒指定延時的精度,數值越小定時器事件解析度越高。預設值為1ms。
         LpTimeProc:指向一個回撥函式。
         DwUser:存放使用者提供的回撥資料。
         FuEvent:指定定時器事件型別:
         TIME_ONESHOT:uDelay毫秒後只產生一次事件
         TIME_PERIODIC :每隔uDelay毫秒週期性地產生事件。