In our product we have code that can be simplified to essentially this function:
#include <boost/asio/steady_timer.hpp>
#include <functional>
void DelayedCall(
boost::asio::io_service& io,
boost::asio::steady_timer::duration delay,
std::function<void()> f)
{
auto timer = std::make_shared<boost::asio::steady_timer>(io, delay);
timer->async_wait(
[timer, f](boost::system::error_code const&)
{
// Probably it's ok to do even this:
//timer.reset();
f();
}
);
}
Assume that io
object has global lifetime for simplicity.
As you can see timer object will be destroyed in handler's destructor.
When this question come to my mind, I was beware of some references in timer to executing handler and vise versa. I know that timer destructor will call cancel on all async waiting handlers, but this is irrelevant as handler already executing and can not be canceled.
Now I think that timer object simply post()
s handler to io_service
when time comes, so both timer and handler become independent from each other. Nevertheless quick attempt to investigate asio source code failed, so I'm still not certain that our code is correct.
I didn't find anything relevant in documentation neither here nor here.
This is safe and well-defined for all I/O objects.
Boost.Asio has taken efforts to support using shared_ptr
to extend the lifetime of an object, such as a steady_timer
, to be at least as long as a sequence of asynchronous operations by binding a shared_ptr
to the object into the handlers. The documentation notes:
[...] permits programs to simplify their resource management by using
shared_ptr<>
. Where an object's lifetime is tied to the lifetime of a connection (or some other sequence of asynchronous operations), ashared_ptr
to the object would be bound into the handlers for all asynchronous operations associated with it.
To support this, initiating functions accept handlers by-value, and Boost.Asio is responsibility for maintaining the validity of the handler. The implementation may make copies of the handler, and all copies are guaranteed to be destroyed:
io_service
is destroyedio_service::service
that owns the handler is shutdown via shutdown_service()
The requirements on asynchronous operations documentation states:
Arguments to initiating functions will be treated as follows:
— If the parameter is declared as a const reference or by-value, the program is not required to guarantee the validity of the argument after the initiating function completes. The implementation may make copies of the argument, and all copies will be destroyed no later than immediately after invocation of the handler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With