15

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?

Peeter Joot
  • 7,848
  • 7
  • 48
  • 82
  • Possible duplicate of [How to make thread sleep less than a millisecond on Windows](http://stackoverflow.com/questions/85122/how-to-make-thread-sleep-less-than-a-millisecond-on-windows) – Ben Voigt Feb 04 '16 at 18:02

6 Answers6

11

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.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
7

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
Community
  • 1
  • 1
user541686
  • 205,094
  • 128
  • 528
  • 886
  • 4
    You should point out that this is an undocumented, unsupported API for the sake of full disclosure ;-) – David Heffernan Oct 19 '11 at 20:19
  • 2
    @Damon: Yes, I believe that's what happens. :) Also, I wouldn't worry about this API changing any time soon -- I actually think the kernel API is probably *more* stable than the Win32 API, since Win32 depends on it. (I guess this is arguable, but the point is, I highly doubt it could go away anytime soon.) – user541686 Oct 20 '11 at 00:29
5

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 and WaitForMultipleObjects.
  • In MinGW-W64: nanosleep.c and thread.c (Zope Public License)
    • This is based on 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.

Mingye Wang
  • 1,107
  • 9
  • 32
1

Windows provides Multimedia timers that are higher resolution than Sleep(). The actual resolution supported by the OS can be obtained at runtime.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
1

You may want to look into

timeBeginPeriod / timeEndPeriod

and/or

QueryPerformanceCounter

See here for more information: http://www.geisswerks.com/ryan/FAQS/timing.html particulary the section towards the bottom: High-precision 'Sleeps'

ethanpil
  • 2,522
  • 2
  • 24
  • 34
-1

Yeah there is , under 'pthread.h' mingw compiler

Hassen Dhia
  • 555
  • 4
  • 11