是否有Windows等效的nanosleep?

Pee*_*oot 7 winapi

Unix有各种睡眠API(睡眠,睡眠,纳米睡眠).我知道睡眠的唯一Win32功能是Sleep(),它以毫秒为单位.

我看到大多数睡眠,即使在Unix上,也会大幅度上升(即:通常为大约10ms).我在Solaris上看到过,如果你以root身份运行,你可以获得10毫秒以下的休眠时间,我知道如果启用了精细粒度计时器内核参数,这也可以在HPUX上运行.Windows上是否有更精细的粒度计时器?如果是,那么什么是API?

Jer*_*fin 6

可悲的事实是,对此没有好的答案.多媒体计时器可能是你可以得到的最接近的 - 它们只允许你将周期设置为1毫秒,但是(由于timeBeginPeriod)它们实际上提供了大约1毫秒的精度,其中大多数其他只做大约10-15毫秒作为一个规则.

还有很多其他候选人.乍一看,CreateWaitableTimerSetWaitableTimer可能看起来最接近的等效,因为他们在100个纳秒interals已经设置.不幸的是,至少在我的测试中,你不能真正依赖于接近那个好分辨率的任何地方.从长远来看,它们可能确实提供了最好的可能性,因为它们至少可以让您指定小于1毫秒的时间,即使您当前无法依赖实现来提供(接近)该分辨率.

NtDelayExecution似乎大致相同,SetWaitableTimer只是它没有记录.除非您已经开始使用/测试未记录的函数,否则在我看来,CreateWaitableTimer/ SetWaitableTimer只是在记录的基础上更好的选择.

如果您正在使用线程池,则可以尝试使用CreateThreadPoolTimerSetThreadPoolTimer不是.我没有对它们进行足够的测试以确定它们真正提供的分辨率,但我并不是特别乐观.

定时器队列(CreateTimerQueue,CreateTimerQueueTimer等)是MS建议用作多媒体定时器的替代品,但是(至少在我的测试中)它们实际上并没有提供比它更好的分辨率Sleep.


Meh*_*dad 5

如果你只是想解决在纳秒范围内,还有NtDelayExecutionntdll.dll

NTSYSAPI NTSTATUS NTAPI NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval);
Run Code Online (Sandbox Code Playgroud)

它以 100 纳秒的间隔测量时间。

但是,这可能不是您想要的:

它可以延迟更长的时间——只要一个线程时间片(0.5 - 15 毫秒)或两个。
您可以使用以下代码来观察这一点:

#ifdef __cplusplus
extern "C" {
#endif
#ifdef  _M_X64
typedef long long intptr_t;
#else
typedef int intptr_t;
#endif
int __cdecl printf(char const *, ...);
int __cdecl _unloaddll(intptr_t);
intptr_t __cdecl _loaddll(char *);
int (__cdecl * __cdecl _getdllprocaddr(intptr_t, char *, intptr_t))(void);
typedef union _LARGE_INTEGER *PLARGE_INTEGER;
typedef long NTSTATUS;
typedef NTSTATUS __stdcall NtDelayExecution_t(unsigned char Alertable, PLARGE_INTEGER Interval); NtDelayExecution_t *NtDelayExecution = 0;
typedef NTSTATUS __stdcall NtQueryPerformanceCounter_t(PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency); NtQueryPerformanceCounter_t *NtQueryPerformanceCounter = 0;
#ifdef __cplusplus
}
#endif

int main(int argc, char *argv[]) {
    long long delay = 1 * -(1000 / 100) /* relative 100-ns intervals */, counts_per_sec = 0;
    long long counters[2];
    intptr_t ntdll = _loaddll("ntdll.dll");
    NtDelayExecution = (NtDelayExecution_t *)_getdllprocaddr(ntdll, "NtDelayExecution", -1);
    NtQueryPerformanceCounter = (NtQueryPerformanceCounter_t *)_getdllprocaddr(ntdll, "NtQueryPerformanceCounter", -1);
    for (int i = 0; i < 10; i++) {
        NtQueryPerformanceCounter((PLARGE_INTEGER)&counters[0], (PLARGE_INTEGER)&counts_per_sec);
        NtDelayExecution(0, (PLARGE_INTEGER)&delay);
        NtQueryPerformanceCounter((PLARGE_INTEGER)&counters[1], (PLARGE_INTEGER)&counts_per_sec);
        printf("Slept for %lld microseconds\n", (counters[1] - counters[0]) * 1000000 / counts_per_sec);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的输出:

Slept for 9455 microseconds
Slept for 15538 microseconds
Slept for 15401 microseconds
Slept for 15708 microseconds
Slept for 15510 microseconds
Slept for 15520 microseconds
Slept for 1248 microseconds
Slept for 996 microseconds
Slept for 984 microseconds
Slept for 1010 microseconds
Run Code Online (Sandbox Code Playgroud)

  • 为了全面披露,您应该指出这是一个未记录、不受支持的 API ;-) (2认同)
  • @Damon:是的,我相信就是这样。:) 另外,我不会担心这个 API 会很快改变——我实际上认为内核 API 可能比 Win32 API *更*稳定,因为 Win32 依赖于它。(我想这是有争议的,但关键是,我非常怀疑它会很快消失。) (2认同)

Art*_*2e5 5

MinGW 的详细回答是:

MinGW 和 Cygwin 在<pthread.h>. 源代码:

  • 在 Cygwin 和 MSYS2 中:signal.cccygwait.cc(LGPLv3+;有链接异常)
    • 这是基于NtCreateTimerWaitForMultipleObjects
  • 在 MinGW-W64 中:nanosleep.cthread.c(Zope 公共许可证)
    • 这是基于WaitForSingleObjectSleep

此外,gnulib (GPLv3+) 在nanosleep.c中有更高精度的实现。QueryPerformanceCounter这会在短(<1s)间隔和Sleep较长间隔内执行忙循环。

timeBeginPeriod您可以使用与所有底层 NT 计时器相关联的常用技巧 ethanpil。