Is there a Windows equivalent of nanosleep?
If you merely want resolution in the nanoseconds range, there's NtDelayExecution
in ntdll.dll
:
NTSYSAPI NTSTATUS NTAPI NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval);
It measures time in 100-nanosecond intervals.
HOWEVER, this probably isn't what you want:
It can delay for much longer than that—as long as a thread time slice (0.5 - 15ms) or two.
Here's code you can use to observe this:
#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;
}
My output:
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
The sad truth is that there is no good answer to this. Multimedia timers are probably the closest you can get -- they only let you set periods down to 1 ms, but (thanks to timeBeginPeriod
) they do actually provide precision around 1 ms, where most of the others do only about 10-15 ms as a rule.
There are a lot of other candidates. At first glance, CreateWaitableTimer
and SetWaitableTimer
probably seem like the closest equivalent since they're set in 100 ns interals. Unfortunately, you can't really depend on anywhere close to that good of resolution, at least in my testing. In the long term, they probably do provide the best possibility, since they at least let you specify a time of less than 1 ms, even though you can't currently depend on the implementation to provide (anywhere close to) that resolution.
NtDelayExecution
seems to be roughly the same, as SetWaitableTimer
except that it's undocumented. Unless you're set on using/testing undocumented functions, it seems to me that CreateWaitableTimer
/SetWaitableTimer
is a better choice just on the basis of being documented.
If you're using thread pools, you could try using CreateThreadPoolTimer
and SetThreadPoolTimer
instead. I haven't tested them enough to have any certainty about the resolution they really provide, but I'm not particularly optimistic.
Timer queues (CreateTimerQueue
, CreateTimerQueueTimer
, etc.) are what MS recommends as the replacement for multimedia timers, but (at least in my testing) they don't really provide much better resolution than Sleep
.
The MinGW answer in long form:
MinGW and Cygwin provides a nanosleep() implementation under <pthread.h>
. Source code:
- In Cygwin and MSYS2: signal.cc and cygwait.cc (LGPLv3+; with linking exception)
- This is based on
NtCreateTimer
andWaitForMultipleObjects
.
- This is based on
- In MinGW-W64: nanosleep.c and thread.c (Zope Public License)
- This is based on
WaitForSingleObject
andSleep
.
- This is based on
In addition, gnulib (GPLv3+) has a higher-precision implementation in nanosleep.c. This performs a busy-loop over QueryPerformanceCounter
for short (<1s) intervals and Sleep
for longer intervals.
You can use the usual timeBeginPeriod
trick ethanpil linked to with all the underlying NT timers.