簡介
這篇文章是說明如何使用C#做高精度的計時器,有些時候,我們會需要用到精準度更高的計時器及Sleep,但Sleep的精準度並不高
因此只好自己客制化了
背景
在一般的系統中,Sleep(1)其實是相當於15.625ms(1/64秒),也就是說Sleep(15)以下都是Sleep一樣的時間.
微軟MSDN參考資料
源碼
[StructLayout(LayoutKind.Sequential)]<br />public struct MSG<br />{<br /> public IntPtr handle;<br /> public uint msg;<br /> public IntPtr wParam;<br /> public IntPtr lParam;<br /> public uint time;<br /> public System.Drawing.Point p;<br />}<br />public class AccurateTimer<br />{<br /> public static bool IsTimeBeginPeriod = false;</p><p> const int PM_REMOVE = 0x0001;</p><p> [DllImport("kernel32.dll", SetLastError = true)]<br /> static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin,<br /> uint wMsgFilterMax, uint wRemoveMsg);</p><p> [DllImport("kernel32.dll", SetLastError = true)]<br /> static extern bool TranslateMessage(ref MSG lpMsg);</p><p> [DllImport("kernel32.dll", SetLastError = true)]<br /> static extern bool DispatchMessage(ref MSG lpMsg);</p><p> [DllImport("kernel32.dll", SetLastError = true)]<br /> public static extern bool QueryPerformanceCounter(ref Int64 count);</p><p> [DllImport("kernel32.dll", SetLastError = true)]<br /> public static extern bool QueryPerformanceFrequency(ref Int64 frequency);</p><p> public static int GetTimeTick()<br /> {<br /> return Environment.TickCount;<br /> }</p><p> public static void AccurateSleep(int a_i4MSec)<br /> {<br /> Int64 t_i8Frequency = 0;<br /> Int64 t_i8StartTime = 0;<br /> Int64 t_i8EndTime = 0;<br /> double t_r8PassedMSec = 0;<br /> MSG msg;<br /> AccurateTimer.QueryPerformanceCounter(ref t_i8StartTime);<br /> AccurateTimer.QueryPerformanceFrequency(ref t_i8Frequency);<br /> do<br /> {<br /> if (AccurateTimer.PeekMessage(out msg, IntPtr.Zero, 0, 0, PM_REMOVE))<br /> {<br /> AccurateTimer.TranslateMessage(ref msg);<br /> AccurateTimer.DispatchMessage(ref msg);<br /> }<br /> AccurateTimer.QueryPerformanceCounter(ref t_i8EndTime);<br /> t_r8PassedMSec = ((double)(t_i8EndTime - t_i8StartTime) / (double)t_i8Frequency) * 1000;<br /> } while (t_r8PassedMSec <= a_i4MSec);<br /> }<br />}
說明
QueryPerformanceFrequency:可以取得每秒CPU的Performance Tick
QueryPerformanceCounter:可以取得CPU運行到現在的Tick數
在這個程式範例中,我自行寫了一個AccurateSleep,這個函數的目的是因為Sleep的精準度只有15.625毫秒
如果只有計時器精準,但是Sleep卻不精準,那怎麼樣也無法測出15.625毫秒以下的精準度
但是如果僅用while loop做等待,那卻會造成程式無回應,因此在迴圈中,需要再處理Windows的訊息,避免程式無回應
參考資料