這裏是我覺得你以後實際上是同時問這個問題的細節:
SetTimer的()會先掃描非內核定時器列表(雙向鏈表),看看是否計時器ID已經存在。如果定時器存在,它將被簡單地重置。如果不是,則發生HMAllocObject調用併爲該結構創建空間。計時器結構將被填充並鏈接到列表的頭部。
這將是創建每個100個定時器的總開銷。這正是例程所做的,除了檢查最小和最大dwElapsed參數。只要定時器到期,定時器列表就會在(大約)最後定時器列表掃描期間看到的最小定時器持續時間的持續時間內掃描。 (實際上,真正發生的是 - 內核定時器被設置爲找到的最小用戶定時器的持續時間,並且該內核定時器喚醒線程,該線程檢查用戶定時器到期並通過設置標誌來喚醒相應的線程他們的消息隊列狀態)。
對於列表中的每個定時器,當前時間(以毫秒爲單位)時,從列表中的每個定時器遞減當前時間(以毫秒爲單位)。當到期時(< = 0),它在自己的結構中被標記爲「就緒」,並且從定時器結構讀取線程信息的指針,並通過設置線程的QS_TIMER標誌來喚醒相應的線程。然後它增加你的消息隊列的CurrentTimersReady計數器。這就是所有計時器到期時間。沒有發佈實際消息。
當你的主消息泵調用的GetMessage(),當沒有其他可用的消息,GetMessage函數()檢查您的線程的喚醒位QS_TIMER,如果設置 - 生成由掃描完整的用戶定時器列表中的WM_TIMER消息列表中標記爲READY並且與您的線程ID相關聯的最小定時器。然後它減少線程的CurrentTimersReady計數,如果爲0,則清除定時器喚醒位。下一次調用GetMessage()將導致相同的事情發生,直到所有計時器耗盡。
一次性定時器保持實例化。當它們到期時,它們被標記爲等待。下一次調用具有相同計時器ID的SetTimer()將僅更新並重新激活原始。無論是一個鏡頭還是週期性定時器都會自行重置,並且只有在KillTimer或您的線程或窗口被銷燬時纔會死機。
Windows的實現是非常基礎的,我認爲編寫更高性能的實現對你來說是微不足道的。
我不使用WM_TIMER。我使用無窗計時器(傳遞時間proc指針直接:: SetTimer())。問題是關於如何集中創建/銷燬定時器內核對象以及多少這樣的對象可能同時存在而沒有任何問題是很昂貴的。謝謝。 – Stas 2011-05-05 08:22:45
您總是使用WM_TIMER。 GetMessage合成消息,而DispatchMessage - 當傳遞帶有空hwnd的WM_TIMER消息時,將其直接分發給TimerProc/LPARAM。 – 2011-05-05 09:15:13
我不確定「當消息循環檢測到火災時」的含義。它的工作方式是系統線程管理用戶計時器的完整列表,並執行火災檢測並設置標誌以喚醒正確的線程。 GetMessage將看到該標誌,如果沒有其他消息存在,必須去實際挖掘該定時器。線程唯一知道的是1)計時器被觸發,2)被觸發多少次。 GetMessage必須實際進行一次調用才能掃描整個用戶計時器列表,並找到與您的線程關聯的最早的一個。你的下一個GetMessage發現下一個,等等。 – James 2017-11-28 07:43:59