想過沒有? WaitableTimer 是在 "定時等待", 前面例子中的 WaitForSingleObject 等待函數 "也在等待", 這就 "雙重等待" 了, 這不好, 太浪費資源.
其實作為同步工具, 前面的幾種方法(事件、訊號、臨界區)基本夠用了; WaitableTimer 的作用並不是為了重複前面的功能, 它的主要功用類似 TTimer 類; 譬如每隔多長時間執行一段代碼、或在指定的時間去執行一段代碼.
既然有了方便的 TTimer, 何必再使用 WaitableTimer 呢?
因為 WaitableTimer 比 TTimer 精確的多, 它的間隔時間可以精確到毫秒、它的指定時間甚至是精確到 0.1 毫秒;
而 TTimer 驅動的 WM_TIMER 訊息, 是訊息佇列中優先順序最低的, 也就是再同一時刻 WM_TIMER 訊息總是被最後處理.
還有重要的一點 WaitableTimer 可以跨線程、跨進程使用.
繼續探討一個重要的點: 很多時候為了讓線程不衝突, 線程也在等待, 既然有等待, 那 WaitableTimer 非常精確的定時又有什麼價值呢? 對這個問題的思考, 可以讓我們很好地理解 APC 函數.
SetWaitableTimer 有個回呼函數(其實是個過程), Windows 要求它的格式是:
procedure TimerAPCProc(
lpArgToCompletionRoutine: Pointer;
dwTimerLowValue: DWORD;
dwTimerHighValue: DWORD
); stdcall;
函數名中有 APC 的字樣, 指示這是個 APC 函數(儘管這個名稱無所謂, 這是官方命名), 那什麼是 APC 函數?
APC(Asyncroneus Procedure Call): 非同步程序呼叫.
原來每個線程除了有單獨的訊息佇列, 還有一個 APC 隊列(等待執行的 APC 函數); 如果線程發現 APC 隊列中有情況, 馬上會跳過去執行, 執行完畢後才回來接著處理訊息佇列.
說起來麻煩, 使用的時候只按上面格式傳入函數指標就行; 不過能進入 APC 隊列的回呼函數和其他回呼函數還有一個很大的不同:
SetWaitableTimer 按格式調用 APC 函數後, 需要在 "當前線程" 見到一個 "等待", 此 APC 函數才可以進入隊列.
這好像很費解, 例說一下: APC 隊列有那麼高的優先順序, 因為對資源的優先使用會對其他訊息有很大的影響, 肯定不能隨便進入, 這是不是像生活中的貴賓席或貴賓通道?
也就是說, 要進入 APC 隊列只有 SetWaitableTimer 的調用還不夠, 還要通過 "等待函數" 介紹一下.
WaitForSingleObject 嗎? 不是, 它不夠層級; 下面是 Windows 認可的、可以介紹 APC 入列的等待函數:
SleepEx();
WaitForSingleObjectEx();
WaitForMultipleObjectsEx();
MsgWaitForMultipleObjectsEx();
SignalObjectAndWait();