解決上一節中延時函數占CPU使用率(達50%)的第二種方法是利用消息機制,通過API函數MsgWaitForMultipleObjects等待消息或超時的到來,從而避免使用循環檢測使CPU占用率過高。完整的改進版Delay函數代碼如下:
- procedure Delay(dwMilliseconds:DWORD);
- var
- endTick: DWORD;
- Event: THandle;
- begin
- Timer1.Enabled:=False;
- Event := CreateEvent(nil,False,False,nil);
- try
- endTick := GetTickCount+dwMilliseconds;
- while (dwMilliseconds > 0) and
- (MsgWaitForMultipleObjects(1, Event, False,
- dwMilliseconds, QS_ALLINPUT) = WAIT_OBJECT_0+1) do
- begin //還在延時期間且有輸入消息則執行下面的分發消息
- Application.ProcessMessages;
- dwMilliseconds := endTick-GetTickcount;
- end;
- finally
- CloseHandle(Event); //關閉事件句柄,銷毀事件對象
- end;
- Timer1.Enabled:=True;
- end;
- {用到的兩個API函數}
- //***********************************************************************
- //函數:CreateEvent //創建事件對象
- //參數:lpEventAttributes=nil //默認的安全符
- // bManualReset=False //自動復原:當事件被一個等待線程釋放以后,
- // //系統將會自動將事件狀態復原為無信號狀態
- // bInitialState=False //指定事件對象的初始狀態為無信號狀態
- // lpName=nil //無名對象
- //返回值:事件對象句柄
- //***********************************************************************
- //**************************************************************************
- //函數:MsgWaitForMultipleObjects //等待直到返回條件滿足則立即返回
- //
- //返回條件:①指定(信號)事件對象(第二個參數)中的一個或所有(第三個參數)對象發出信號
- //(任意一個 ②指定的等待/超時時間(第四個參數)已到
- //滿足即可) ③指定的消息(第五個參數)已抵達線程的輸入隊列
- //
- //參數: nCount=1 指定列表中的句柄數量為1
- // pHandles=Event 指定對象句柄組合中的第一個元素為Event
- // fWaitAll=False 任何對象發出信號即可
- // dwMilliseconds=dwMilliseconds 等待的毫秒數為延時時間
- // dwWakeMask=QS_ALLINPUT 標識特定的消息類型為消息隊列的任何消息
- //返回值:WAIT_OBJECT_0+1(nCount) 有指定類型的消息到達
- //*************************************************************************
以下是MSDN中關於MsgWaitForMultipleObjects的一段說明:
The MsgWaitForMultipleObjects function determines whether the wait criteria have been met. If the criteria have not been met, the calling thread enters an efficient wait state, using very little processor time while waiting for the conditions of the wait criteria to be met.
MsgWaitForMultipleObjects判斷等待條件(即返回條件)是否滿足,如果不滿足,調用線程(在此即主線程)進入高效的等待狀態:使用非常少的CPU時間來等候返回條件成立。
更多關於MsgWaitForMultipleObjects的介紹請參見http://msdn.microsoft.com/zh-cn/library/ms931460
測試
利用以上提到的三個函數:Sleep、Delay、改進的Delay,進行了一個簡單的測試,結果截圖如下:
(1) 使用Sleep
(2)使用Delay
(3)使用改進版Delay
分析總結:
① Sleep函數掛起了程序,使界面和定時器都得不到響應,當然更不會占用CPU了。
② Delay函數采用循環檢測方式,雖然界面能得到及時響應,但在延時的5秒時間內CPU占用率達到了50%。
③ 改進的Delay函數即能響應界面,CPU使用率也很低(幾乎為0,只在有指定輸入消息到達時才有1%)。
④ 后兩個函數對於窗體關閉消息也不能及時響應。
http://blog.csdn.net/tht2009/article/details/6685622