Jason Aubrey
2011-12-30 23:24:05 UTC
Overview:
I'm trying to use a deadline_timer in an RAII context as shown below.
Details:
When a deadline_timer goes out of scope, it would be nice (at least I think so) if it encapsulated the cleanup logic by implicitly canceling queued handlers and ensuring pending handlers are completed. Since this is not the case, I need to explicitly synchronize the cleanup as shown below.
//--------------------------------------------------------------------------------
struct foo
{
foo(boost::asio::io_service& io_service)
: m_timer(io_service)
{
schedule_timer();
}
~foo()
{
m_timer.cancel();
m_event.wait();
}
void schedule_timer()
{
m_timer.expires_at(boost::posix_time::microsecond_clock() + boost::posix_time::seconds(1));
m_timer.async_wait(boost::bind(&foo::on_timer, this, boost::asio::placeholders::error));
}
void on_timer(const boost::system::error_code& code)
{
if(code == boost::asio::error::operation_aborted)
{
m_event.signal();
return;
}
// TODO: Handle spurious wake-ups (omitted for brevity)
// TODO: Modify this instance (omitted for brevity)
schedule_timer();
}
boost::asio::deadline_timer m_timer;
manual_reset_event m_event; // An abstraction based on condition_variable, mutex, and a bool
};
//--------------------------------------------------------------------------------
Analysis:
Reasons I don't like the code above:
*) Not sure it is correct - any idea?
*) Prone to a deadlock if an exception is thrown in on_timer before schedule_timer is called again
*) Need an event for every timer to ensure cleanup
The only alternatives I've come across are:
1) Use static functions for the handlers to avoid lifetime issues
2) Have the handler self-manage its lifetime (e.g. have it call 'delete this')
3) Couple the timer and io_service lifetimes so the io_service is stopped while the handler is still in scope
A problem I have with each alternative:
1) Even if the handler is static, the handler is modifying an instance which has the same lifetime issues
2) If I need multiple timers in foo then I don't see how 'delete this' is possible where 'this' is an instance of foo.
3) Doesn't fit the situation where timers with independent lifetimes share the same io_service
Please show me something obvious I've missed here!
Thanks,
Jason Aubrey
I'm trying to use a deadline_timer in an RAII context as shown below.
Details:
When a deadline_timer goes out of scope, it would be nice (at least I think so) if it encapsulated the cleanup logic by implicitly canceling queued handlers and ensuring pending handlers are completed. Since this is not the case, I need to explicitly synchronize the cleanup as shown below.
//--------------------------------------------------------------------------------
struct foo
{
foo(boost::asio::io_service& io_service)
: m_timer(io_service)
{
schedule_timer();
}
~foo()
{
m_timer.cancel();
m_event.wait();
}
void schedule_timer()
{
m_timer.expires_at(boost::posix_time::microsecond_clock() + boost::posix_time::seconds(1));
m_timer.async_wait(boost::bind(&foo::on_timer, this, boost::asio::placeholders::error));
}
void on_timer(const boost::system::error_code& code)
{
if(code == boost::asio::error::operation_aborted)
{
m_event.signal();
return;
}
// TODO: Handle spurious wake-ups (omitted for brevity)
// TODO: Modify this instance (omitted for brevity)
schedule_timer();
}
boost::asio::deadline_timer m_timer;
manual_reset_event m_event; // An abstraction based on condition_variable, mutex, and a bool
};
//--------------------------------------------------------------------------------
Analysis:
Reasons I don't like the code above:
*) Not sure it is correct - any idea?
*) Prone to a deadlock if an exception is thrown in on_timer before schedule_timer is called again
*) Need an event for every timer to ensure cleanup
The only alternatives I've come across are:
1) Use static functions for the handlers to avoid lifetime issues
2) Have the handler self-manage its lifetime (e.g. have it call 'delete this')
3) Couple the timer and io_service lifetimes so the io_service is stopped while the handler is still in scope
A problem I have with each alternative:
1) Even if the handler is static, the handler is modifying an instance which has the same lifetime issues
2) If I need multiple timers in foo then I don't see how 'delete this' is possible where 'this' is an instance of foo.
3) Doesn't fit the situation where timers with independent lifetimes share the same io_service
Please show me something obvious I've missed here!
Thanks,
Jason Aubrey