Есть ли в Windows эквивалент наноспала? - PullRequest
7 голосов
/ 19 октября 2011

Unix имеет множество API для сна (sleep, usleep, nanosleep).Единственная известная мне Win32 функция для сна - Sleep (), которая выражается в миллисекундах.

Я видел, что большинство снов, даже в Unix, значительно округляются (то есть: обычно до 10 мс).Я видел, что в Solaris, если вы работаете от имени пользователя root, вы можете получить сны менее 10 мс, и я знаю, что это возможно и в HPUX при условии, что включен параметр ядра для точных зернистых таймеров.Доступны ли более точные таймеры гранулярности в Windows, и если да, то каковы API?

Ответы [ 5 ]

6 голосов
/ 20 октября 2011

Печальная правда в том, что нет хорошего ответа на это. Таймеры мультимедиа, вероятно, самые близкие, которые вы можете получить - они позволяют устанавливать периоды только до 1 мс, , но (благодаря timeBeginPeriod), они действительно обеспечивают точность около 1 мс, где большинство других делайте, как правило, только 10-15 мс.

Есть много других кандидатов. На первый взгляд, CreateWaitableTimer и SetWaitableTimer, вероятно, кажутся самым близким эквивалентом, поскольку они установлены в 100 нс. К сожалению, вы не можете зависеть от такого разрешения, по крайней мере, в моем тестировании. В долгосрочной перспективе они, вероятно, предоставляют наилучшую возможность, поскольку, по крайней мере, позволяют вам указать время менее 1 мс, хотя в настоящее время вы не можете зависеть от реализации, обеспечивающей (где-либо близко) это разрешение.

NtDelayExecution кажется примерно таким же, как SetWaitableTimer, за исключением того, что он не имеет документов. Если вы не настроены на использование / тестирование недокументированных функций, мне кажется, что CreateWaitableTimer / SetWaitableTimer - лучший выбор только на основании документации.

Если вы используете пулы потоков, вы можете попробовать использовать CreateThreadPoolTimer и SetThreadPoolTimer. Я недостаточно тестировал их, чтобы иметь уверенность в том, какое разрешение они действительно предоставляют, но я не особенно оптимистичен.

Очереди таймеров (CreateTimerQueue, CreateTimerQueueTimer и т. Д.) - это то, что MS рекомендует в качестве замены мультимедийных таймеров, но (по крайней мере, в моем тестировании) они на самом деле не обеспечивают намного лучшее разрешение, чем Sleep.

2 голосов
/ 19 октября 2011

Если вы просто хотите разрешение в диапазоне наносекунд, есть NtDelayExecution в ntdll.dll:

NTSYSAPI NTSTATUS NTAPI NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval);

Измеряет время с интервалом в 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;
}

Мой вывод:

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
1 голос
/ 19 октября 2011

Возможно, вы захотите взглянуть на

timeBeginPeriod / timeEndPeriod

и / или

QueryPerformanceCounter

Для получения дополнительной информации см. Здесь: http://www.geisswerks.com/ryan/FAQS/timing.html В частности, раздел внизТочность 'Спит'

1 голос
/ 19 октября 2011

Windows предоставляет Мультимедийные таймеры с более высоким разрешением, чем Sleep(). Фактическое разрешение, поддерживаемое ОС, можно получить во время выполнения.

0 голосов
/ 17 сентября 2017

Да, есть, под компилятором 'pthread.h' mingw

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...