Boost logo

Boost Users :

Subject: Re: [Boost-users] Boost.ASIO calling handler guarantees
From: Sorin Fetche (sorin.fetche_at_[hidden])
Date: 2014-08-22 15:00:08


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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net