views:

227

answers:

2

What I mean is, let's say you do an async_wait on an asio timer and bind the update to a function that takes a reference to a type T. Let's say you created the T initially on the stack before passing it to async_wait. At the end of that async_wait, it calls async_wait itself, renewing the timer over and over. Does that stack allocated type T stay alive until the first time the timer doesn't renew itself, or after the first invocation of the function will the T go out of scope?

A: 

I have no experience with asio timers. But if you do

void somefunc( void )
{
  boost::asio::io_service io;

  boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
}

Then the timer is out of scope when it exit the function. So with this code no wait ever happen. If you add t.wait() to that code it will wait 5s and exit the function and the timer is out of scope.

void somefunc( void )
{
  boost::asio::io_service io;

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

  io.run();
}

In the second example the timer goes out of scope when function exit.

If you want to loop around the timer I guess you have to write like this.

void somefunc( void )
{
  boost::asio::io_service io;

  while( something )
  {
    boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
    t.async_wait(somecallback);

    io.run();
  }
}

That will keep the timer on the stack for one turn in the loop, and then it is re-created. If you put the timer outside the loop it will never go out of scope. But then you have to reset it some way ever turn in the loop. But I do not see any such function.

EDIT: In the example of async_wait(), the timer will be destroy, out of scope, directly without finish if you do not have the io.run() to make it wait. And I would guess that the desructor of deadline_timer() will do a cancel of the timer when it hit the destructor.

jpyllman
+1  A: 

If you were to write a function in which you create a timer on the stack, then call async_wait, the timer would be destroyed at the end of the function call, and the callback immediately called with the proper error parameter.

You cannot pass the timer object to the callback using boost::bind, as the object is non copyable.

Nevertheless, you can manage your binder on the heap, passing a shared pointer on each call to async_wait. This could look like this:

void MyClass::addTimer(int milliseconds) // Initial timer creation call
{
  boost::shared_ptr<boost::asio::deadline_timer> t
    (new boost::asio::deadline_timer
     (m_io_service, 
      boost::posix_time::milliseconds(milliseconds)));
  // Timer object is being passed to the handler
  t->async_wait(boost::bind(&MyClass::handle_timer,
                            this,
                            t,
                            milliseconds));

}

void MyClass::handle_timer(boost::shared_ptr<boost::asio::deadline_timer> & t,
                               int milliseconds)
{
  // Push the expiry back using the same tick
  t->expires_at(t->expires_at() + boost::posix_time::milliseconds(milliseconds));
  t->async_wait(boost::bind(&MyClass::handle_timer,
                            this,
                            t,
                            milliseconds));
  onTimer(); // Do something useful
}
small_duck