
On Fri, Aug 22, 2014 at 5:30 AM, Niall Douglas wrote:
On 22 Aug 2014 at 16:20, wrote:
Under which circumstances is it guaranteed that asynchronous operation completion handler is called? [snip] Not relying on this assumption what is the reliable way of building applications with Boost.Asio?
I asked something similar sometime ago, so I'm glad this subject is raised again. http://article.gmane.org/gmane.comp.lib.boost.devel/243496
I can't speak for ASIO, but AFIO explicitly makes no guarantees if a bad_alloc exception is ever thrown. Otherwise it guarantees exception safety.
I would be highly surprised if ASIO can do any better than AFIO here. Handling bad_alloc is extremely tough when your exception handling paths have no choice but to allocate memory, which for something involving async i/o they must.
After more recent experimentation in a project consisting of a stack of increasingly complex functionality following the Proactor design (the Boost.Asio flavor of it), it has become apparent that one cannot rely on the completion handler of an operation to be called. Especially if using an allocator that does throw bad_alloc (and does it often under testing conditions). This is because, once the completion handler becomes less trivial, even its copy constructor may throw right before being executed by the io_service. The only solution I found so far for coping with the possibility of missing handler calls is for each each of them to carry a RAII / guard object that, if destructed before being "disabled", triggers the closing of the context which waits for the completion handler. The premise of this approach is that an io_service is shared by multiple independent contexts each doing asynchronous operations internally, so outside io_service::run() there is little or no context on how to handle an exception coming out of it. The two main assumptions for such a close-guard solution to work are: - An exception bubbling through io_service::run will not cause handlers to leak - they are either destroyed or called successfully - close() functions do not throw as they will be potentially called from a destructor during exception stack unwinding. This is the other aspect I raised in my email from a year ago; how come close() functions fail in Boost.Asio and what is one supposed to do with that failure at least in the context of commit/rollback? Best regards, Sorin Fetche