Reputation: 992
I'm trying to create a routine in C that would execute some code every X ms.
I have done it in C# but i need this program in C.
I have tried to implement it using time(0) or clock(), but the problem with these functions is that i can have the system wait a certain amount of time after executing some code.
My intention is to have code executed in chunks of time X. say X is 25ms execute some code. afterwards if i have still time left nothing has to be done until X = 25
If otherwise i have used 30 ms to perform my action i'll have to wait until the next clock tick to do other stuff.
Thank you in advance for any advice.
Upvotes: 1
Views: 509
Reputation: 28828
Below is windows code example similar to multi-threaded games where one of the threads runs at a fixed frequency as accurately as possible. The delays are based on an original reading of a high precision timer, so there's no drift over time. dwLateStep (see example code below) is a debugging aid that gets incremented if a time step is exceeded (the code attempts to catch back up). Sleep(1) can take up to 2 ms on Windows XP, so the code uses Sleep(1) when there is more than 2 ms of delay before the next time step.
However this is different than your description, where it seems you have code that may take longer than a time step. In this case, you run the code in fragments, one fragment for each time step. Say there are 4 fragments, then you could use a switch variable that cycles by 1 on each time step from 0 to 3 then back to 0, with 4 cases.
/* code for a thread to run at fixed frequency */
typedef unsigned long long UI64; /* unsigned 64 bit int */
#define FREQ 400 /* frequency */
DWORD dwLateStep; /* late step count */
LARGE_INTEGER liPerfFreq; /* 64 bit frequency */
LARGE_INTEGER liPerfTemp; /* used for query */
UI64 uFreq = FREQ; /* process frequency */
UI64 uOrig; /* original tick */
UI64 uWait; /* tick rate / freq */
UI64 uRem = 0; /* tick rate % freq */
UI64 uPrev; /* previous tick based on original tick */
UI64 uDelta; /* current tick - previous */
UI64 u2ms; /* 2ms of ticks */
UI64 i;
/* ... */ /* wait for some event to start thread */
QueryPerformanceFrequency(&liPerfFreq);
u2ms = ((UI64)(liPerfFreq.QuadPart)+499) / ((UI64)500);
timeBeginPeriod(1); /* set period to 1ms */
Sleep(128); /* wait for it to stabilize */
QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
uOrig = uPrev = liPerfTemp.QuadPart;
for(i = 0; i < (uFreq*30); i++){
/* update uWait and uRem based on uRem */
uWait = ((UI64)(liPerfFreq.QuadPart) + uRem) / uFreq;
uRem = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq;
/* wait for uWait ticks */
while(1){
QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
uDelta = (UI64)(liPerfTemp.QuadPart - uPrev);
if(uDelta >= uWait)
break;
if((uWait - uDelta) > u2ms)
Sleep(1);
}
if(uDelta >= (uWait*2))
dwLateStep += 1;
uPrev += uWait;
/* fixed frequency code goes here */
/* along with some type of break when done */
}
timeEndPeriod(1); /* restore period */
Upvotes: 1
Reputation: 64
You have to create new thread with an infinite loop which will tick (approximately) every 25 ms.
Upvotes: 1
Reputation: 92966
The functions I use in this answer are POSIX functions. On non-POSIX systems like Windows, these functions might not be available.
The general approach to this kind of problem is to get the system to deliver you a signal every 25 ms or whatever the duration is you have to wait for. One way to do this is to set a timer (e.g. with setitimer
) and have the signal handler for the corresponding signal (i.e. SIGALRM
or SIGVTALRM
) rearm the timer once it elapsed. You can then do your computations and use the pause
system call to “wait” for the next signal to interrupt you.
If your time periods get much shorter than that, signal delivery might be too slow for your use case. You could call the clock
function to get the amount of time you used in a loop and wait until it's close enough to a multiple of 25 ms. This approach has less latency than an approach based on signals, but it keeps your processor busy, so only use it if the duration you have to wait for is really short. This approach has the advantage of being very portable as clock
is part of standard C.
A third approach is to get the current time and then compute the time you need to wait until the next tick happens and then call nanosleep
or a similar function to wait for that time. This approach is imprecise (you might sleep for a little more than the time you want to sleep for), but it doesn't cause any drift because you synchronize yourself with the clock every time you find out the current time.
Upvotes: 2