Boost logo

Boost Users :

Subject: Re: [Boost-users] boost::asio::deadline_timer precision issues
From: Igor R (boost.lists_at_[hidden])
Date: 2010-03-01 11:29:39


> The solution works, however the timer seems to have (important) precision
> issues, as described in the sample code below. A simple counter is
> incremented every 20 ms, and is displayed (and reset) every 1000 ms. The
> value displayed should therefore be close to 50. In practice, it's closer to
> 40, which in unexplainable with such a simple piece of code.

The timer is ok, but pay attention that every time you call the
handler and then reset the timer, you accumulate an inaccuracy. The
1st timer fires much frequently than the 2nd, thus it accumulates much
more inaccuracy.
You can solve this problem by introducing a reference time and build on it.
Here's how your code should be modified:

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

static boost::asio::io_service* s_service = 0;
static unsigned int s_counter = 0;

struct timer
{
 timer(unsigned int delay, boost::function< void () > callback) :
   m_timer(*s_service),
   m_callback(callback),
   m_delay(delay)
 {
 }

 void start()
 {
  m_timeBase = boost::posix_time::microsec_clock::universal_time();
  do_start();
 }

 void do_start()
 {
   m_elapsed = boost::posix_time::microsec_clock::universal_time() - m_timeBase;
   m_timer.expires_from_now(m_estimated - m_elapsed +
boost::posix_time::millisec(m_delay));
   m_timer.async_wait(boost::bind(&timer::handle_wait, this, _1));
 }

 void handle_wait(const boost::system::error_code& e)
 {
   m_estimated += boost::posix_time::millisec(m_delay);
   do_start();
   m_callback();
 }

 boost::asio::deadline_timer m_timer;
 boost::function< void () > m_callback;
 unsigned int m_delay;
 boost::posix_time::ptime m_timeBase;
 boost::posix_time::time_duration m_estimated, m_elapsed;
};

void increment()
{
 s_counter++;
}

void display()
{
 std::cout << s_counter << std::endl;
 s_counter = 0;
}

int main()
{
 boost::asio::io_service service;
 s_service = &service;

 // Display the counter every 1000ms.
 timer t1(1000, display);
 // Increment the counter every 20ms.
 timer t2(20, increment);

 t1.start();
 t2.start();

 service.run();
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net