30

I want a very simple periodic timer to call my code every 50ms. I could make a thread that sleeps for 50ms all the time (but that's a pain)... I could start looking into Linux API's for making timers (but it's not portable)...

I'd like to use boost.. I'm just not sure it's possible. Does boost provide this functionality?

g19fanatic
  • 10,567
  • 6
  • 33
  • 63
Scott
  • 1,176
  • 2
  • 13
  • 19

5 Answers5

33

A very simple, but fully functional example:

#include <iostream>
#include <boost/asio.hpp>

boost::asio::io_service io_service;
boost::posix_time::seconds interval(1);  // 1 second
boost::asio::deadline_timer timer(io_service, interval);

void tick(const boost::system::error_code& /*e*/) {

    std::cout << "tick" << std::endl;

    // Reschedule the timer for 1 second in the future:
    timer.expires_at(timer.expires_at() + interval);
    // Posts the timer event
    timer.async_wait(tick);
}

int main(void) {

    // Schedule the timer for the first time:
    timer.async_wait(tick);
    // Enter IO loop. The timer will fire for the first time 1 second from now:
    io_service.run();
    return 0;
}

Notice that it is very important to call expires_at() to set a new expiration time, otherwise the timer will fire immediately because it's current due time already expired.

Lucio Paiva
  • 19,015
  • 11
  • 82
  • 104
  • @AndrewStone I don't think so, but if you're worried about that, you can use a steady timer instead, which will not be affected by system time changes. Take a look here: http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/steady_timer.html It should be easy to port my example above to use it. – Lucio Paiva Oct 20 '17 at 23:32
  • 2
    Note that ```boost::asio::io_service::run()``` blocks the thread execution so you cannot execute intructions after calling it and expect the timer to also trigger at the same time. – pandaman1234 Mar 29 '18 at 21:18
  • why is tick allowed to be called without the '()' i.e. shouldn't it be timer.async_wait(tick()); – jaxkewl Apr 26 '19 at 16:32
  • 1
    @jaxkewl the reason is that `tick` isn't being called immediately. Instead, a reference to it is being passed to `async_wait()`, which will eventually call it in the future. – Lucio Paiva Apr 28 '19 at 10:53
  • +1. `expires_at` is *much* more accurate than `expires_after`, which the official examples use. `expires_after` introduces a skew in the timer period and becomes practically useless at high rates. – rustyx Apr 09 '21 at 16:38
21

The second example on Boosts Asio tutorials explains it.
You can find it here.

After that, check the 3rd example to see how you can call it again with a periodic time intervall

kebs
  • 6,387
  • 4
  • 41
  • 70
default
  • 11,485
  • 9
  • 66
  • 102
  • Note that ```boost::asio::io_service::run()``` blocks the thread execution so you cannot execute intructions after calling it and expect the timer to also trigger at the same time. – pandaman1234 Mar 29 '18 at 21:18
  • wait, if IO.run blocks thread execution, what's the point of this being async? – Jake Gaston Mar 25 '19 at 19:48
1

To further expand on this simple example. It will block the execution as was said in the comments, so if you want more io_services running, you should run them in a thread like so...

boost::asio::io_service io_service;
boost::asio::io_service service2;
timer.async_wait(tick);
boost::thread_group threads;
threads.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
service2.run();
threads.join_all();
jaxkewl
  • 195
  • 10
0

As I had some issues with prior answers, here is my example:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

void print(const boost::system::error_code&, boost::asio::deadline_timer* t,int* count)
{
    if (*count < 5)
    {
        std::cout << *count << std::endl;
        ++(*count);
        t->expires_from_now(boost::posix_time::seconds(1));
        t->async_wait(boost::bind(print, boost::asio::placeholders::error, t, count));
    }
}

int main()
{ 
    boost::asio::io_service io;
    int count = 0;
    boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));

    t.async_wait(boost::bind(print, boost::asio::placeholders::error, &t, &count));

    io.run();
    std::cout << "Final count is " << count << std::endl;

    return 0;

}

it did what it supposed to do: counting to five. May it help someone.

0

A Boost Asio add-on class that encapsulates this functionality (call a specfied function every N milliseconds): https://github.com/mikehaben69/boost/tree/main/asio

The repo includes a demo source file and makefile.

Michael Haben
  • 117
  • 1
  • 6