Control loop time with usleep


Control loop time with usleep



I try to make sure the execution time of each loop to 10ms with usleep , but sometimes it exceeds 10ms.



I have no idea how to solve this problem, is it proper to use usleep and gettimeofday in this case?



Please help my find out what i missed.



Result: 0.0127289
0.0136499
0.0151598
0.0114031
0.014801


double tvsecf(){
struct timeval tv;
double asec;

gettimeofday(&tv,NULL);
asec = tv.tv_usec;
asec /= 1e6;
asec += tv.tv_sec;

return asec;
}
int main(){
double t1 ,t2;
t1 = tvsecf();
for(;;){
t2= tvsecf();
if(t2-t1 >= 0.01){
if(t2-t1 >= 0.011)
cout << t2-t1 <<endl;
t1 = tvsecf();
}
usleep(100);
}
}





First, you have to decide which language you are using…
– sidyll
2 days ago





Usually sleeps are only guaranteed to sleep for at least as long as you asked for - they may sleep longer.
– Jesper Juhl
2 days ago






I think nanosleep is the preferred sleep.
– Christian Gibbons
2 days ago


nanosleep





This sounds like a XY problem. What are you actually trying to achieve?
– Jesper Juhl
2 days ago





If you really need to do something every 10ms without fail (and don't just think you do), then you're going to need to run your program on a real-time OS
– Jeremy Friesner
2 days ago




3 Answers
3



To keep the loop overhead (which is generally unknown) from constantly accumulating error, you can sleep until a time point, instead of for a time duration. Using C++'s <chrono> and <thread> libraries, this is incredibly easy:


<chrono>


<thread>


#include <chrono>
#include <iostream>
#include <thread>

int
main()
{
using namespace std;
using namespace std::chrono;
auto t0 = steady_clock::now() + 10ms;
for (;;)
{
this_thread::sleep_until(t0);
t0 += 10ms;
}
}



One can dress this up with more calls to steady_clock::now() in order to ascertain the time between iterations, and perhaps more importantly, the average iteration time:


steady_clock::now()


#include <chrono>
#include <iostream>
#include <thread>

int
main()
{
using namespace std;
using namespace std::chrono;
using dsec = duration<double>;
auto t0 = steady_clock::now() + 10ms;
auto t1 = steady_clock::now();
auto t2 = t1;
constexpr auto N = 1000;
dsec avg{0};
for (auto i = 0; i < N; ++i)
{
this_thread::sleep_until(t0);
t0 += 10ms;
t2 = steady_clock::now();
dsec delta = t2-t1;
std::cout << delta.count() << "sn";
avg += delta;
t1 = t2;
}
avg /= N;
cout << "avg = " << avg.count() << "sn";
}



Above I've added to the loop overhead by doing more things within the loop. However the loop is still going to wake up about every 10ms. Sometimes the OS will wake the thread late, but next time the loop automatically adjusts itself to sleep for a shorter time. Thus the average iteration rate self-corrects to 10ms.



On my machine this just output:


...
0.0102046s
0.0128338s
0.00700504s
0.0116826s
0.00785826s
0.0107023s
0.00912614s
0.0104725s
0.010489s
0.0112545s
0.00906409s
avg = 0.0100014s





Yes! The average iteration time is the most important for my application.
– zhiyo
2 days ago



There is no way to guarantee 10ms loop time.
All sleeping functions sleeps for at least wanted time.
For a portable solution use std::this_thread::sleep_for


#include <iostream>
#include <chrono>
#include <thread>

int main()
{
for (;;) {
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(std::chrono::milliseconds{10});
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end-start;
std::cout << "Waited " << elapsed.count() << " msn";
}
}



Depending on what you are trying to do take a look at Howard Hinnants date library.



From the usleep man page:



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.



If you need high resolution: with C on Unix (or Linux) check out this answer that explains how to use high resolution timers using clock_gettime.



Edit: As mentioned by Tobias nanosleep may be a better option:


Compared to sleep(3) and usleep(3), nanosleep() has the following
advantages: it provides a higher resolution for specifying the sleep
interval; POSIX.1 explicitly specifies that it does not interact with
signals; and it makes the task of resuming a sleep that has been
interrupted by a signal handler easier.





Also from usleep man page. POSIX.1-2001 declares this function obsolete use nanosleep(2) instead. POSIX.1-2008 removes the specification of usleep()
– Tobias
2 days ago






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

Opening a url is failing in Swift

Possible Unhandled Promise Rejection (id: 0): ReferenceError: user is not defined ReferenceError: user is not defined