如何将计时器分辨率设置为0.5毫秒?

9

我想将机器计时器分辨率设置为0.5毫秒。

Sysinternal实用程序报告最小时钟分辨率为0.5毫秒,因此可以完成。

P.S. 我知道如何将其设置为1毫秒。

P.P.S. 我将其从C#更改为更一般的问题(感谢Hans)

系统计时器分辨率


您可以查看此处有关计时器设置和亚毫秒计时器服务的详细信息:http://www.windowstimestamp/description - Arno
5个回答

12

NtSetTimerResolution

示例代码:

#include <windows.h>

extern "C" NTSYSAPI NTSTATUS NTAPI NtSetTimerResolution(ULONG DesiredResolution, BOOLEAN SetResolution, PULONG CurrentResolution);

...

ULONG currentRes;
NtSetTimerResolution(5000, TRUE, &currentRes);

使用ntdll.lib库进行链接。


8
您可以通过使用隐藏的API NtSetTimerResolution() 获得0.5毫秒的分辨率。 NtSetTimerResolution由本机Windows NT库NTDLL.DLL导出。请参见MSDN上的如何将计时器分辨率设置为0.5ms?。然而,真正可实现的分辨率取决于底层硬件。现代硬件确实支持0.5毫秒的分辨率。更多详细信息请参阅《Windows NT高分辨率计时器内部》。可以通过调用NtQueryTimerResolution()来获取支持的分辨率。

操作方法:

#define STATUS_SUCCESS 0
#define STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000245

// after loading NtSetTimerResolution from ntdll.dll:

// The requested resolution in 100 ns units:
ULONG DesiredResolution = 5000;  
// Note: The supported resolutions can be obtained by a call to NtQueryTimerResolution()

ULONG CurrentResolution = 0;

// 1. Requesting a higher resolution
// Note: This call is similar to timeBeginPeriod.
// However, it to to specify the resolution in 100 ns units.
if (NtSetTimerResolution(DesiredResolution ,TRUE,&CurrentResolution) != STATUS_SUCCESS) {
    // The call has failed
}

printf("CurrentResolution [100 ns units]: %d\n",CurrentResolution);
// this will show 5000 on more modern platforms (0.5ms!)

//       do your stuff here at 0.5 ms timer resolution

// 2. Releasing the requested resolution
// Note: This call is similar to timeEndPeriod 
switch (NtSetTimerResolution(DesiredResolution ,FALSE,&CurrentResolution) {
    case STATUS_SUCCESS:
        printf("The current resolution has returned to %d [100 ns units]\n",CurrentResolution);
        break;
    case STATUS_TIMER_RESOLUTION_NOT_SET:
        printf("The requested resolution was not set\n");   
        // the resolution can only return to a previous value by means of FALSE 
        // when the current resolution was set by this application      
        break;
    default:
        // The call has failed

}

注意:NtSetTimerResolution的功能基本上映射到函数timeBeginPeriod和timeEndPeriod上,使用布尔值Set(有关计划及其全部影响的详细信息,请参见Inside Windows NT High Resolution Timers)。但是,多媒体套件将粒度限制为毫秒,并且NtSetTimerResolution允许设置亚毫秒值。

谢谢。那是我4年前发现的...但由于敌对和误导性答案的攻击,我自己回答了它,但尽可能简短(因为显然没有人需要这个)。自从那时以来,我一直在我的实时软件中愉快地使用它(根据大多数“开发者”的说法,在Windows和.NET上不可能编写)。PS我看了你的项目。看起来很有前途...只要注意Windows计时器的“抖动”..你的项目比我的挑战更大!祝好运! - Boppity Bop
根据我的实验,我认为STATUS_TIMER_RESOLUTION_NOT_SET错误代码应该是0xC0000245而不是245。 - Roland Pihlakas
@RolandPihlakas 没错,谢谢。我已经编辑了我的答案进行更正。实际上,这是在MSDN上有记录的 - Arno

4
如果您使用Python,我编写了一个名为wres的库,它在内部调用NtSetTimerResolution。

pip install wres

import wres

# Set resolution to 0.5 ms (in 100-ns units)
# Automatically restore previous resolution when exit with statement
with wres.set_resolution(5000):
    pass

1
也许在这篇文章中添加更多细节会对OP和整个社区更有帮助。 - BusyProgrammer
我的Windows实际测试表明,使用这种方法时,time.sleep()的时间在1ms-1.5ms之间。请用你的代码替换此处列出的'pass'。当增加延迟时间时,它似乎仍会变化约0.5ms。在繁忙的系统中,您可能会获得更差的性能。 - Jacob Waters

3

你可以通过使用timeBeginPeriod和timeSetEvent函数调用来获得Win32 API中的最小时间间隔,其值为1毫秒。也许你的HAL可以做得更好,但这是学术上的问题,因为你不能使用C#编写设备驱动程序代码。


我已经使用了那些。我希望能够在此之下。您知道是否有一个可以做到这一点的实用程序(不一定是C#)?毕竟,我只需要更改系统时钟。 - Boppity Bop
我从C#转到了其他任何语言,只是希望能够完成这个任务。 - Boppity Bop

1

7
在 System.dll 中,被 System.Diagnostics.Stopwatch 取代。 - Charlie Salts
@Charlie Salts:我猜那就是Bobb要找的类吧(+1) - riffnl
2
我不想测量时间,我只需要它更快地滴答。 - Boppity Bop
为什么不使用上述类构建自己的计时器控件 - 附加了一个新的MSDN文章。大多数关于这种定时的解决方案不是使用事件,而是两个“状态”之间经过的时间。 - riffnl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接