1

What is the best way in C++11 to implement a high-resolution timer that continuously checks for time in a loop, and executes some code after it passes a certain point in time? e.g. check what time it is in a loop from 9am onwards and execute some code exactly at 11am. I require the timing to be precise (i.e. no more than 1 microsecond after 9am).

I will be implementing this program on Linux CentOS 7.3, and have no issues with dedicating CPU resources to execute this task.

8
  • @Aconcagua yes. In that case, any suggestions? Commented Sep 16, 2019 at 9:59
  • std::chrono::high_resolution_clock: 'represents the clock with the smallest tick period provided by the implementation'. Commented Sep 16, 2019 at 10:11
  • 3
    Running in a loop appears pretty questionable to me, though, if you need such high precision. At very least, you'll need to make sure that no other processes run on the same core, so that you avoid context switches between threads. Possibly, an interrupt based solution has better chance to reach desired precision. Commented Sep 16, 2019 at 10:14
  • 1
    auto targetTime = std::chrono::high_resolution_clock::now(); /* now get exact time from your atomic clock! With that, calculate exact distance to 11:00 */ targetTime += duration; while(targetTime - std::chrono::high_resolution_clock::now() > 0) { /* wait */ } (calculation for yet being positive time difference has been simplified!). Commented Sep 16, 2019 at 14:20
  • 1
    1us! Wow! OK, waiting in a loop is no solution. This is a real time scheduler requirement. So you should think of using RT kernel in that case. But what is the sense of such a scenario. Typically such things are running on embedded devices with synchronized crystal on board. Keeping the OS clock such precise on a normal PC sounds impossible to me. Have you ever checked how much time deviation your RTC has on your system? BTW: How do you synchronize to the real planet time? Using ntp protocol did not offer such precision! Commented Sep 16, 2019 at 14:47

3 Answers 3

2

Instead of implementing this manually, you could use e.g. a systemd.timer. Make sure to specify the desired accuracy which can apparently be as precise as 1us.

Sign up to request clarification or add additional context in comments.

3 Comments

Is it possible to include systemd.timer in a c++ program? As it is part of a larger program, i'm not able to separate the code out into a program which can be put on systemd.timer.
@L.Koh: A systemd.timer starts a systemd.service. Services start a program, but your already runs.
@L.Koh yes: if your C++ program talks dbus you can also dynamically create & register the timer with systemd.
2

a high-resolution timer that continuously checks for time in a loop,

First of all, you do not want to continuously check the time in a loop; that's extremely inefficient and simply unnecessary.

...executes some code after it passes a certain point in time?

Ok so you want to run some code at a given time in the future, as accurately as possible.

The simplest way is to simply start a background thread, compute how long until the target time (in the desired resolution) and then put the thread to sleep for that time period. When your thread wakes up, it executes the actual task. This should be accurate enough for the vast majority of needs.

The std::chrono library provides calls which make this easy:

Here's a snippet of code which does what you want using the system clock (which makes it easier to set a wall clock time):

// c++ --std=c++11 ans.cpp -o ans

#include <thread>
#include <iostream>
#include <iomanip>

// do some busy work
int work(int count)
{
    int sum = 0;
    for (unsigned i = 0; i < count; i++)
    {
        sum += i;
    }    
    return sum;
}

std::chrono::system_clock::time_point make_scheduled_time (int yyyy, int mm, int dd, int HH, int MM, int SS)
{
    tm datetime = tm{};

    datetime.tm_year = yyyy - 1900; // Year since 1900
    datetime.tm_mon = mm - 1; // Month since January
    datetime.tm_mday = dd; // Day of the month [1-31]
    datetime.tm_hour = HH; // Hour of the day [00-23]
    datetime.tm_min = MM;
    datetime.tm_sec = SS;

    time_t ttime_t = mktime(&datetime);

    std::chrono::system_clock::time_point scheduled = std::chrono::system_clock::from_time_t(ttime_t);

    return scheduled;
}

void do_work_at_scheduled_time()
{
    using period = std::chrono::system_clock::period;

    auto sched_start = make_scheduled_time(2019, 9, 17,  // date
                                           00, 14, 00);  // time

    // Wait until the scheduled time to actually do the work
    std::this_thread::sleep_until(sched_start);

    // Figoure out how close to scheduled time we actually awoke
    auto actual_start = std::chrono::system_clock::now();
    auto start_delta = actual_start - sched_start;
    float delta_ms = float(start_delta.count())*period::num/period::den * 1e3f;

    std::cout << "worker: awoken within " << delta_ms << " ms" << std::endl;

    // Now do some actual work!
    int sum = work(12345);
}

int main()
{
    std::thread worker(do_work_at_scheduled_time);

    worker.join();

    return 0;
}

On my laptop, the typical latency is about 2-3ms. If you use the high_resolution_clock you should be able to get even better results.

There are other APIs you could use too, such as Boost where you could use ASIO to implement high res timeout.

I require the timing to be precise (i.e. no more than 1 microsecond after 9am).

Do you really need it to be accurate to the microsecond? Consider that at this resolution, you will also need to take into account all sorts of other factors, including system load, latency, clock jitter, and so on. Your code can start to execute at close to that time, but that's only part of the problem.

2 Comments

Thanks @gavinb. This is helpful. I have previously also explored struct tm, but the issue seems to be that it is not possible to define tm up to at least milliseconds? Please correct me if I am wrong.
@L.Koh The struct tm is only used to define the scheduled wall clock time (in seconds), which is then converted to a std::chrono::time_point, which is far more accurate (at least ms or better, depending on the OS/platform). So when the time delta is computed for the sleep time, it will be as precise as std::chrono::system_clock::period, microseconds on my machine. But as I mentioned though, there are all sorts of latencies and factors that impact performance.
0

My suggestion would be to use timer_create(). This allows you to get notified by a signal at a given time. You can then implement your action in the signal handler.

In any case you should be aware that the accuracy of course depends on the system clock accuracy.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.