Question

I tried using the boost deadline_timer in this simple test application, but had some trouble. The goal is for the timer to trigger every 45 milliseconds using the expires_at() member function of the deadline_timer. (I need an absolute time, so I'm not considering expires_from_now(). I am also not concerned about drift at the moment). When I run the program, wait() does not wait for 45 ms! Yet, no errors are reported. Am I using the library incorrectly somehow?

Sample program:

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
using namespace std;

int main()
{
        boost::asio::io_service Service;
        boost::shared_ptr<boost::thread> Thread;
        boost::asio::io_service::work RunForever(Service);
        Thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&boost::asio::io_service::run, &Service)));
        boost::shared_ptr<boost::asio::deadline_timer> Timer(new boost::asio::deadline_timer(Service));

        while(1)
        {
                boost::posix_time::time_duration Duration;
                Duration = boost::posix_time::microseconds(45000);
                boost::posix_time::ptime Start = boost::posix_time::microsec_clock::local_time();
                boost::posix_time::ptime Deadline = Start + Duration;
                boost::system::error_code Error;
                size_t Result = Timer->expires_at(Deadline, Error);
                cout << Result << ' ' << Error << ' ';
                Timer->wait(Error);
                cout << Error << ' ';
                boost::posix_time::ptime End = boost::posix_time::microsec_clock::local_time();
                (cout << "Duration = " << (End - Start).total_milliseconds() << " milliseconds" << endl).flush();
        }
        return 0;
}
Was it helpful?

Solution

You are mixing local time with system time. The time that asio is comparing your local time to is most likely some number of hours after the time that you want your deadline set to so wait returns immediately (depending on where you live; this same code could wait for several hours as well). To avoid this point of confusion, absolute times should be derived from asio::time_traits.

#include <boost/asio.hpp>
#include <boost/asio/time_traits.hpp>
#include <boost/thread.hpp> 
#include <boost/bind.hpp> 
#include <boost/date_time/posix_time/posix_time.hpp> 
#include <iostream> 
using namespace std;

typedef boost::asio::time_traits<boost::posix_time::ptime> time_traits_t;  
int main() {         
    boost::asio::io_service Service;         
    boost::shared_ptr<boost::thread> Thread;         
    boost::asio::io_service::work RunForever(Service);         
    Thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&boost::asio::io_service::run, &Service)));
    boost::shared_ptr<boost::asio::deadline_timer> Timer(new boost::asio::deadline_timer(Service));          
    while(1)         
    {                 
        boost::posix_time::time_duration Duration;
        Duration = boost::posix_time::microseconds(45000);
        boost::posix_time::ptime Start = time_traits_t::now();
        boost::posix_time::ptime Deadline = Start + Duration;
        boost::system::error_code Error;
        size_t Result = Timer->expires_at(Deadline, Error);
        cout << Result << ' ' << Error << ' ';
        Timer->wait(Error);
        cout << Error << ' ';
        boost::posix_time::ptime End = boost::posix_time::microsec_clock::local_time();
        (cout << "Duration = " << (End - Start).total_milliseconds() << " milliseconds" << endl).flush();
     }         
    return 0; 
}

That should work out for you in this case.

OTHER TIPS

You are mixing asynchronous methods io_service::run with synchronous methods deadline_timer::wait. This will not work. Either use deadline_timer::async_wait with io_service::run, or skip the io_service::run and just use deadline_timer::wait. You also don't need a thread to invoke io_service:run if you go the asynchronous route, one thread will do just fine. Both concepts are explained in detail in the Basic Skills section of the Asio tutorial.

void print(const boost::system::error_code& /*e*/)
{
  std::cout << "Hello, world!\n";
}

int main()
{
  boost::asio::io_service io;

  boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
  t.async_wait(print);
  io.run();

  return 0;
}

Note you will need to give some work for your io_service to service prior to invoking run(). In this example, async_wait is that work.

Potentially unrelated: 45ms is quite a small delta. In my experience the smallest time for any handler to make it through the Asio epoll reactor queue is around 30 ms, this can be considerably longer at higher loads. Though it all largely depends on your application.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top