这篇文章是说明如何使用C#做高精度的计时器,有些时候,我们会需要用到精准度更高的计时器及Sleep,但Sleep的精准度并不高
因此只好自己客制化了
背景
在一般的系统中,Sleep(1)其实是相当于15.625ms(1/64秒),也就是说Sleep(15)以下都是Sleep一样的时间.
源码
- [StructLayout(LayoutKind.Sequential)]
- public struct MSG
- {
- public IntPtr handle;
- public uint msg;
- public IntPtr wParam;
- public IntPtr lParam;
- public uint time;
- public System.Drawing.Point p;
- }
- public class AccurateTimer
- {
- public static bool IsTimeBeginPeriod = false;
- const int PM_REMOVE = 0x0001;
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin,
- uint wMsgFilterMax, uint wRemoveMsg);
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern bool TranslateMessage(ref MSG lpMsg);
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern bool DispatchMessage(ref MSG lpMsg);
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern bool QueryPerformanceCounter(ref Int64 count);
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern bool QueryPerformanceFrequency(ref Int64 frequency);
- public static int GetTimeTick()
- {
- return Environment.TickCount;
- }
- public static void AccurateSleep(int a_i4MSec)
- {
- Int64 t_i8Frequency = 0;
- Int64 t_i8StartTime = 0;
- Int64 t_i8EndTime = 0;
- double t_r8PassedMSec = 0;
- MSG msg;
- AccurateTimer.QueryPerformanceCounter(ref t_i8StartTime);
- AccurateTimer.QueryPerformanceFrequency(ref t_i8Frequency);
- do
- {
- if (AccurateTimer.PeekMessage(out msg, IntPtr.Zero, 0, 0, PM_REMOVE))
- {
- AccurateTimer.TranslateMessage(ref msg);
- AccurateTimer.DispatchMessage(ref msg);
- }
- AccurateTimer.QueryPerformanceCounter(ref t_i8EndTime);
- t_r8PassedMSec = ((double)(t_i8EndTime - t_i8StartTime) / (double)t_i8Frequency) * 1000;
- } while (t_r8PassedMSec <= a_i4MSec);
- }
- }
说明
QueryPerformanceFrequency:可以取得每秒CPU的Performance Tick
QueryPerformanceCounter:可以取得CPU运行到现在的Tick数
在这个程式范例中,我自行写了一个AccurateSleep,这个函数的目的是因为Sleep的精准度只有15.625毫秒
如果只有计时器精准,但是Sleep却不精准,那怎么样也无法测出15.625毫秒以下的精准度
但是如果仅用while loop做等待,那却会造成程式无回应,因此在回圈中,需要再处理Windows的讯息,避免程式无回应