I want to execute once a specific action delayed n seconds after the last asynchronous event occurred. So if successive events appear in less that n seconds, the specific action is delayed (deadline_timer is restarted).
I adapted the timer class from boost deadline_timer issue and for simplicity the events are generated synchronously. Running the code, I’m expecting something like:
1 second(s)
2 second(s)
3 second(s)
4 second(s)
5 second(s)
action <--- it should appear after 10 seconds after the last event
but I get
1 second(s)
2 second(s)
action
3 second(s)
action
4 second(s)
action
5 second(s)
action
action
Why does this happen? How to solve this?
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>
class DelayedAction
{
public:
DelayedAction():
work( service),
thread( boost::bind( &DelayedAction::run, this)),
timer( service)
{}
~DelayedAction()
{
thread.join();
}
void startAfter( const size_t delay)
{
timer.cancel();
timer.expires_from_now( boost::posix_time::seconds( delay));
timer.async_wait( boost::bind( &DelayedAction::action, this));
}
private:
void run()
{
service.run();
}
void action()
{
std::cout << "action" << std::endl;
}
boost::asio::io_service service;
boost::asio::io_service::work work;
boost::thread thread;
boost::asio::deadline_timer timer;
};
int main()
{
DelayedAction d;
for( int i = 1; i < 6; ++i)
{
Sleep( 1000);
std::cout << i << " second(s)\n";
d.startAfter( 10);
}
}
PS Writing this, I’m thinking the true issue is how boost::deadline_timer can be restarted once it was started.
When you call
expires_from_now()it resets the timer, and the handler is immediately called with the error codeboost::asio::error::operation_aborted.If you handle the error code case in your handler, then you can make this work as expected.
This is discussed in the documentation:
http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/reference/deadline_timer.html
See specifically the section titled: Changing an active deadline_timer’s expiry time