計時器(Timer)是一種在編程中用于測量時間間隔的機制。它允許程序在指定的時間間隔內執行特定的操作或觸發事件。
本節必須掌握的知識點:
??? ????計時器
7.1.1 計時器
我們可以調用SetTimer函數為自己的Windows程序分配一個計時器。SetTimer包含一個無符號整型參數,該參數指定了時間間隔的長短,為一毫秒(millisecond)到4 294 967 295 毫秒(將近50天)。這個參數也表示Windows給程序發送WM_TIMER消息的頻率。例如, 1000毫秒就是要求Windows每一秒鐘向你的程序發送一條WM_TIMER消息。
當程序不再需要計時器時,它可調用KillTimer函數停止計時器的消息。在處理 WM_TIMER消息時調用KillTimer函數可以實現一個“一次性”的計時器。KillTimer函數會淸除消息隊列中任何沒被處理的WM_TIMER消息。調用了 KillTimer之后,程序就不會再收到WM_TIMER消息了。
?????? ■Windows系統計時器
在 Windows 系統中,計時器的實現原理涉及到系統時鐘和消息循環。
Windows 系統中的計時器通常使用以下兩種方式實現:
●基于時間片的計時器(基于輪詢):這種計時器的實現方式是在應用程序的消息循環中以固定時間間隔進行輪詢。應用程序通過在消息循環中處理 WM_TIMER 消息來執行特定的操作。WM_TIMER 消息會周期性地發送給應用程序的消息隊列,以通知計時器事件的發生。
應用程序可以使用 SetTimer 函數來創建一個定時器。該函數指定計時器的時間間隔和回調函數,并返回一個計時器 ID。然后,在消息循環中,應用程序通過處理 WM_TIMER 消息來執行相應的操作。
這種基于時間片的計時器適用于較低精度的計時需求,例如執行周期性的任務或更新用戶界面。
●高精度計時器(Multimedia Timers):對于需要更高精度和準確性的計時需求,Windows 提供了高精度計時器。高精度計時器使用系統時鐘的硬件定時器來實現,提供了更高的計時精度。
應用程序可以使用 timeSetEvent 函數來創建一個高精度計時器。該函數指定計時器的時間間隔、回調函數和其他參數,并返回一個計時器 ID。計時器事件觸發時,系統會調用指定的回調函數。
高精度計時器適用于需要更精確計時的場景,例如音頻和視頻處理、實時數據采集等。
無論是基于時間片的計時器還是高精度計時器,它們的實現都依賴于系統時鐘和消息循環。系統時鐘提供了時間基準,用于確定計時器事件的發生時間。消息循環負責接收和處理計時器相關的消息,以便應用程序可以在計時器事件發生時執行相應的操作。
需要注意的是,計時器的精度可能受到系統負載、硬件性能和操作系統版本等因素的影響。因此,在實際應用中,如果需要更高精度的計時器,可以使用高精度計時器,并進行適當的性能測試和調優。
■基于時間片的計時器
Windows的應用程序并不截獲BIOS中斷。Windows本身會處理硬件中斷,應用程序不需介入。對于當前所設定的每一個計時器,Windows都會保持一個計數值,硬件時鐘滴答每出現一次,這個值會減1。當計數值減到0,Windows會把一個WM_TIMER消息放到適當的應用程序的消息隊列中,同時把計數值重新設置回它的原始值。
由于Windows應用程序是通過正常的消息隊列來接收WM_TIMER消息,所以你絕對不用擔心程序在處理其他任務時會被突然而來的WM_TIMER消息所“中斷” 。因此計時器與鍵盤和鼠標相似:驅動程序會處理異步硬件中斷事件,Windows則將這些事件轉換為有序的、有組織的和系列化的消息。
在Windows 98上,計時器具有與底層PC計時器相同的55毫秒的周期。而在Windows NT上,計時器的周期大約是10毫秒。
Windows應用程序不能接收比上述頻率更高的WM_TIMER消息,也就是說在 Windows 98上約為每秒18.2次,而在Windows NT上為每秒100次。Windows會通過 SetTimer把指定的時間間隔舍入到時鐘滴答的整數倍。例如,1000亳秒時間段被54.925除是18.207個時鐘滴答,它被舍入到18個時鐘滴答,因此實際的間隔是989毫秒。如果時間間隔被設置為少于55毫秒,每個時鐘滴答都將產生一個WM_TIMER消息。
?????? ■計時器同步
因為計時器是基于硬件計時器的中斷,程序員有時會被誤導,認為他們的程序可能會被異步中斷打斷后被迫去處理WM_TIMER消息。
其實WM_TIMER消息并不是異步的。WM_TIMER消息被放在正常的消息隊列中,并和其他的消息一同排隊等候處理。因此如果你在調用SetTimer函數時指定1000毫秒,并不能保證程序每秒鐘或者每989毫秒(如我前面說過的)就收到一個WM_TIMER消息。如果你的程序處于忙的狀態超過一秒鐘,它就會在那個時間內得不到任何WM_TIMER消息。本章提供的程序便是證明。事實上,Windows處理WM_TIMER消息和處理WM_PAINT消息很類似。這兩種消息都是低優先級的,只有當消息隊列中沒有其他消息時,程序才會收到它們。
WM_TIMER消息還在另一方面與WM_PAINT消息極為類似。Windows并不會連續不斷地產生多個WM_TIMER消息到消息隊列中。相反,Windows把在消息隊列里的多個 WM_TIMER消息結合成一條消息。這樣,應用程序不會同時收到大量的WM_TIMER消息,盡管它可能會收到靠得很近的兩個WM_TIMER消息。同時,應用程序并不知道有多少這樣的WM_TIMER消息在這個過程中“丟失”了。
因此,一個時鐘程序不能通過計算它所收到的WM_TIMER消息個數來確認已過去多長時間。WM_TIMER消息只能告訴應用程序,更新的時間到了。在本章的后面,我們會寫兩個時鐘程序,它們每秒鐘更新一次,我們將準確地看到它是如何實現的。
為方便起見,我將假設計時器每秒鐘收到一個WM_TIMER消息。但是請記住,這些消息不是精確的時鐘滴答中斷。