Временная задержка в C. usleep
Я разрабатываю игровой сервер, который написан на C. И мне нужно разработать цикл с определенной частотой (50 раз в секунду)
для выполнения алгоритма.
Проблема в том, что я не могу приостановить программу на точный временной интервал - 20000 микросекунд.
Функция usleep(20000)
работает около 30000 микросекунд.
Результат всегда больше на 10000 микросекунд, чем ожидалось.
Вот мой простой пример кода:
#include <stdio.h>
#include <time.h>
#include <unistd.h>
int main( int argc, char ** argv )
{
const unsigned long long nano = 1000000000;
unsigned long long t1, t2;
struct timespec tm;
for(;;)
{
clock_gettime( CLOCK_REALTIME, &tm );
t1 = tm.tv_nsec + tm.tv_sec * nano;
usleep( 20000 );
clock_gettime( CLOCK_REALTIME, &tm );
t2 = tm.tv_nsec + tm.tv_sec * nano;
printf( "delay: %ld\n", ( t2 - t1 ) / 1000 );
}
return 0;
}
И результат его выполнения:
$ ./a.out
delay: 29233
delay: 29575
delay: 29621
delay: 29694
delay: 29688
delay: 29732
delay: 29709
delay: 29706
delay: 29666
delay: 29702
delay: 29702
delay: 29705
delay: 29789
delay: 29619
delay: 29785
delay: 29634
delay: 29692
delay: 29708
delay: 29701
delay: 29703
Я также попытался использовать функцию select()
, но результат будет таким же, как с sleep()
.
Объясните мне, пожалуйста, что не так с моим кодом.
p.s:.
$ uname -a
FreeBSD home.com 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan 3 07:46:30 UTC 2012 [email protected]:/usr/obj/usr/src/sys/GENERIC amd64
Ответы
Ответ 1
Вместо того, чтобы спать в течение 20000 секунд, спать на время, оставшееся до повторного запуска, на основе вызова clock_gettime
то есть:
usleep( lasttime+20000-now ); // But make sure you don't sleep when the result is negative
Это не то, что у вашего кода есть проблема, но фактический вызов спать, чтение времени и т.д. требует времени, и система не может спать в течение точного времени в любом случае, если это не кратно его точным часам цикл
Ответ 2
Спящие функции в системах, отличных от реального времени, не гарантируют спящий точный период; на занятой системе процесс будет разбужен только тогда, когда начнется его срез времени. Или как показывает страница man, "активность системы может продлить время ожидания на неопределенное количество".
Значение, близкое к 10 мс, как частота kern.hz
опускается до 100, как некоторые рекомендуют для настроек VM.
Классическим обходным решением для этой проблемы является тот, который предлагается Офиром: вместо указания фиксированного интервала сна укажите оставшееся время для сна. В среднем ваш цикл будет выполняться каждые 20 мс, чего вы, скорее всего, захотите достичь.