Recently i’ve been trying to create a wait function that waits for 25 ms using the wall clock as reference. I looked around and found “gettimeofday”, but i’ve been having problems with it. My code (simplified):
while(1)
{
timeval start, end;
double t_us;
bool release = false;
while (release == false)
{
gettimeofday(&start, NULL);
DoStuff();
{
gettimeofday(&end, NULL);
t_us = ( (end.tv_sec - start.tv_sec) * 1000*1000) + (end.tv_usec - start.tv_usec);
if (t_us >= 25000) //25 ms
{
release = true;
}
}
}
}
This code runs in a thread (Posix) and, on it’s its own, works fine. DoStuff() is called every 25ms. It does however eat all the CPU if it can (as you might expect) so obviously this isn’t a good idea.
When I tried throttling it by adding a Sleep(1); in the wait loop after the if statement, the entire thing slows by about 50% (that is, it called DoStuff every 37ms or so. This makes no sense to me – assuming DoStuff and any other threads complete their tasks in under (25 – 1) ms the called rate of DoStuff shouldn’t be affected (allowing a 1ms error margin)
I also tried Sleep(0), usleep(1000) and usleep(0) but the behaviour is the same.
The same behaviour occurs whenever another higher priority thread needs CPU time (without the sleep). It’s as if the clock stops counting when the thread reliqnuishes runtime.
I’m aware that gettimeofday is vulnerable to things like NTP updates etc… so I tried using clock_gettime but linking -ltr on my system causes problems so i don’t think that is an option.
Does anyone know what i’m doing wrong?
The part that’s missing here is how the kernel does thread scheduling based on time slices. In rough numbers, if you sleep at the beginning of your time slice for 1ms and the scheduling is done on a 35ms clock rate, your thread may not execute again for 35ms. If you sleep for 40ms, your thread may not execute again for 70ms. You can’t really change that without changing the scheduling, but that’s not recommended due to overall performance implications of the system. You could use a “high-resolution” timer, but often that’s implemented in a tight cycle-wasting loop of “while it’s not time yet, chew CPU” so that’s not really desirable either.
If you used a high-resolution clock and queried it frequently inside of your DoStuff loop, you could potentially play some tricks like run for 30ms, then do a sleep(1) which could effectively relinquish your thread for the remainder of your timeslice (e.g. 5ms) to let other threads run. Kind of a cooperative/preemptive multitasking if you will. It’s still possible you don’t get back to work for an extended period of time though…