zhiyo
zhiyo

Reputation: 11

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);
    }
}

Upvotes: 0

Views: 1198

Answers (3)

Howard Hinnant
Howard Hinnant

Reputation: 218700

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:

#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:

#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() << "s\n";
        avg += delta;
        t1 = t2;
    }
    avg /= N;
    cout << "avg = " << avg.count() << "s\n";
}

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

Upvotes: 3

Michael Powers
Michael Powers

Reputation: 2050

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.

Upvotes: 0

Tobias
Tobias

Reputation: 845

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() << " ms\n";
    }
}

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

Upvotes: 0

Related Questions