I'm developing the game server, which is written on C. And I need to develop a cycle with a certain frequency (50 times per second)
to perform an algorithm.
The problem is that I can't pause the program for an exact time interval - 20000 microseconds.
Function usleep(20000)
runs about 30000 microseconds.
The result is always more on 10000 microseconds than expected.
Here is my simple example of code:
#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;
}
And the result of it's running:
$ ./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
I also tried to use function select()
, but result is the same as with the sleep()
.
Explain to me, please, what's wrong with my code.
p.s.:
$ uname -a
FreeBSD home.com 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan 3 07:46:30 UTC 2012 root@farrell.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC amd64
The function usleep() is a C API that suspends the current process for the number of microseconds passed to it. It can be used for delaying a job.
There's nothing obsolete about usleep.
The usleep() function suspends execution of the calling thread for (at least) usec microseconds. The sleep may be lengthened slightly by any system activity or by the time spent processing the call or by the granularity of system timers.
The difference between sleep() and usleep() is that sleep() takes a number of seconds as its parameter, whereas usleep() takes a number of microseconds - millionths of a second - as its parameter.
Instead of sleeping for 20000 useconds, sleep for the time left till you want to run again, based on the call to clock_gettime
I.e:
usleep( lasttime+20000-now ); // But make sure you don't sleep when the result is negative
It is not that your code has a problem, but the actual call to sleep, reading the time, etc. takes time, and the system can't sleep for the exact time anyway unless it is a multiple of its exact clock cycle
Sleeping functions on non-realtime systems are not guaranteed to sleep the exact period specified; on a busy system, the process will be woken up only when its time slice begins. Or, as the man page puts it, "system activity may lengthen the sleep by an indeterminate amount".
The close-to-10ms amount sounds like the kern.hz
frequency is lowered to 100, as some recommend for VM setups.
The classic workaround for this problem is the one offered by Ofir: instead of specifying a fixed sleeping interval, specify the remaining time to sleep. In average, your loop will run every 20ms, which is what you most likely want to achieve.
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