Unix has a variety of sleep APIs (sleep, usleep, nanosleep). The only Win32 function I know of for sleep is Sleep(), which is in units of milliseconds.
I seen that most sleeps, even on Unix, get rounded up significantly (ie: typically to about 10ms). I've seen that on Solaris, if you run as root, you can get sub 10ms sleeps, and I know this is also possible on HPUX provided the fine grain timers kernel parameter is enabled. Are finer granularity timers available on Windows and if so, what are the APIs?
The MinGW answer in long form:
MinGW and Cygwin provides a nanosleep() implementation under <pthread.h>
. Source code:
NtCreateTimer
and WaitForMultipleObjects
.WaitForSingleObject
and Sleep
.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.
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.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With