添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

精确定时的用途基本上分为两种:延时;定时.

支配性参数-- Timer Resolution

操作系统任务切换有时间片的概念,即每到达一个时间片 系统就可以调度一次,来完成任务切换及多个线程的分时复用;

该时间片也就是操作系统运行时的时间分辨率:该值并不固定,可以通过 timeGetDevCaps 来获取,得到的时间片是毫秒(ms)级别.

可以修改时间片来提高Thread.Sleep()及定时器的精度.修改方法见MSDN Timer Resolution .

实际上可以通过一些Windows没有公开的API将时间片提高到微秒(us)级别,类似于timeGetDevCaps的对应API为 NtQueryTimerResolution ,修改时间片的对应API为 NtSetTimerResolution . 详细描述见 Microsecond Resolution Time Services for Windows .

使用方法如下:

 1 typedef NTSTATUS (CALLBACK* NTSETTIMERRESOLUTION)
 3          IN ULONG DesiredTime,
 4          IN BOOLEAN SetResolution,
 5          OUT PULONG ActualTime
 6 );
 7 NTSETTIMERRESOLUTION NtSetTimerResolution;
 9 typedef NTSTATUS (CALLBACK* NTQUERYTIMERRESOLUTION)
10 (
11         OUT PULONG MaximumTime,
12         OUT PULONG MinimumTime,
13         OUT PULONG CurrentTime
14 );
15 NTQUERYTIMERRESOLUTION NtQueryTimerResolution;
17 void QueryTimerResolution(void){
19     HMODULE hNtDll = LoadLibrary(TEXT("NtDll.dll"));
20     if (hNtDll)
21     {
22             NtQueryTimerResolution = (NTQUERYTIMERRESOLUTION)GetProcAddress(hNtDll,"NtQueryTimerResolution");
23             NtSetTimerResolution = (NTSETTIMERRESOLUTION)GetProcAddress(hNtDll,"NtSetTimerResolution");
24             FreeLibrary(hNtDll);
25     }
26     if (NtQueryTimerResolution == NULL || NtSetTimerResolution  ==  NULL){
27         printf("Search function failed!\n");
28         return ;
29     }
31     NTSTATUS nStatus;
33     ULONG Min=0;
34     ULONG Max=0;
35     ULONG Cur=0;
36     nStatus = NtQueryTimerResolution(&Max, &Min,&Cur);
38     printf("NtQueryTimerResolution -> \nMax=%lu(100ns) Min=%lu(100ns) Cur=%lu(100ns)\n",Min,Max,Cur);
40     //BOOL bSetResolution = TRUE;
41     //ULONG nActualTime;
42     //ULONG nDesiredTime = 20064;
43     //nStatus =  NtSetTimerResolution (nDesiredTime, bSetResolution,&nActualTime);

有个小软件(Timer Resolution)可以获取并设置为最大时间分辨率.

对应于精确延时可以采用QueryPerformanceCounterQueryPerformanceFrequency;

前一个函数用来获取性能计数器值,后一个函数来获取性能计数器的频率.将所需延时转换成对应的性能计数器差值,然后不断查询,等到延时时间到达.这也是Windows操作系统所能达到的“最精确的延时".

当然,也可以通过其他途径来比较时间获取完成延时功能:

  • GetTickCount
  • GetTickCount64
  • GetSystemTime
  • GetSystemTimeAsFileTime
  • 在文章Implement a Continuously Updating, High-Resolution Time Provider for Windows 中对可以获取当前毫秒(ms)及的时间函数做了比较,由于函数底层实现的不同,采用QueryPerformanceCounter函数运行时间较长.GetSystemTimeAsFileTime是其中执行时间最短的函数.但是并没有比较GetTickCount.

    在文章APIs you never heard of - the Timer APIs的评论中,写到:

    Centaur, QPC is heavyweight, and is documented as such. timeGetTime is faster but much less accurate. 

    I actually checked the code for timeGetTime and GetTickCount(). GetTickCount() takes the number of clock interrupts and multiplies it by the clock frequency. timeGetTime() reads a field called the "interrupt time", which is updated periodically by the kernel (I wasn't able to find out how frequently).

    对于精确定时可选的方式有(WinAPI):

  • SetTimer
  • CreateTimerQueueTimer
  • timeSetEvent(MSDN建议使用CreateTimerQueueTimer替代)
  • 在文章On WinAPI timers and their resolution中,作者对这三种方式都进行了对比,并以性能计数器为参考,得出结论

    timeSetEvent定时最为精确,误差较小,CreateTimerQueueTimer次之,SetTimer最差.

    对于多任务的Windows来讲,程序执行过程中不能保证不会发生任务切换的情况,故而,精确定时/延时都不会得到保证,就如文章Implement a Continuously Updating, High-Resolution Time Provider for Windows最后的结论.

     Just don't perform anything requiring real-time predictability on the basis of time stamps in Windows NT.

    当然,对于定时/延时要求并不非常苛刻的情况下,得到ms+级别的精度依然是可能的.采用前文所述调整系统时间分辨率(针对部分计算机可达到0.5ms甚至更低),误差会在一个或者数个时间分辨率.

    综上所述:

    如果进行定时操作,可以采用timeSetEvent或者CreateTimerQueueTimer,后者相对更为灵活.

    如果进行延时操作,试图延时在ms一下,采用QueryPerformanceCounter的方式;在ms级别可以采用timeGetTime和GetSystemTimeAsFileTime,抑或GetTickCount.或者说简简单单使用Thread.Sleep(),针对MSDN所述其典型误差在20-60ms,这是对于XP且系统时间分辨率过大来讲的.

    如果试图在Windows上得到更为精确的延时/定时,尝试使用Timer Resolution或者前文所述的方法增大系统时间分辨率,但是系统任务调度等都要付出性能代价,增大系统时间分辨率可能会导致性能方面的损耗.这方面也值得考量.

  • Microsecond Resolution Time Services for Windows.
  • Implement a Continuously Updating, High-Resolution Time Provider for Windows
  • APIs you never heard of - the Timer APIs
  • On WinAPI timers and their resolution
  • VC中基于 Windows 的精确定时
  •