Hi,


thanks for the clarifications!


> Asio itself doesn't catch any exceptions -- if a handler throws then it will be propagated out and into the method that calls io_context.run() -- if this doesn't have a try-catch block wrapped around it by the user then the thread and the app will be terminated.

Yes, I was aware of that, I just wrote it imprecisely. What I meant is what you wrote 😊 (i.e., that coroutine machinery arranges for correct exception propagation from the callee to the caller).


Unrelated: do you have advice on error-handling patterns? Given two "loops", one that reads data from a socket and another that writes data to a socket. Currently, I handle errors with the following pattern:


error_code ec;

something_async(…, ec);

if (!HandleError(ec, "something_async"))

return; // shared_from_this() pattern


where HandleError is defined as


bool HandleError(const error_code& ec, const char* what)
{
    if (IsCanceled() || !_socket.is_open() || ec == boost::system::errc::operation_canceled)
        return false;
    if (!ec)
        return true;
    throw Failure(WeakSelf(), ec, what);
}

(IsCanceled() returns the state of an internal Boolean flag.)

because 1) the same io service thread is running multiple workers, 2) I need to know _which_ worker failed because the worker is associated with "extra data" in the io_service thread and this data may contain "restart" policy (e.g. reconnect on broken connection). Also, the outer loop will cancel the worker in case Failure() has been thrown.

But this seems to combine the worst of two worlds, as both exceptions and error codes are used. If I don't pass error_code to async calls, asio will throw system_error, but that one is not descriptive enough for my purposes.

Is there a way to automate this, or some other recommended "pattern" to use?

-- Stian



From: Boost-users <boost-users-bounces@lists.boost.org> on behalf of Gavin Lambert via Boost-users <boost-users@lists.boost.org>
Sent: Monday, December 17, 2018 10:28 PM
To: boost-users@lists.boost.org
Cc: Gavin Lambert
Subject: Re: [Boost-users] Understanding fibers
 
On 18/12/2018 02:07, Stian Zeljko Vrba wrote:
>  1. The above is inside a _/coroutine/_ and invoked as a callback? (my
>     guess: the caller – asio thread – arranges/provides a catch context
>     that the exception propagates into)
>  2. The above is inside a _/fiber/_ and called by yielding to the fiber
>     scheduler? (my guess: the fiber scheduler does not provide an outer
>     catch context, so the program crashes).
>
> Is this correct?

Yes, both of those are somewhat correct.  Though there are some missing
links.

With coroutines, you're yielding to a specific other coroutine -- if
that coroutine throws, then the exception is thrown out of the yield
point just as if it were a regular function call.

Asio itself doesn't catch any exceptions -- if a handler throws then it
will be propagated out and into the method that calls io_context.run()
-- if this doesn't have a try-catch block wrapped around it by the user
then the thread and the app will be terminated.

Fibers aren't allowed to propagate exceptions into the fiber scheduler,
since you can't customise the exception handling there -- but if you
don't call your fiber code directly but instead wrap it in a
packaged_task, this gives you a future and also wraps the code in a
try-catch block such that if the code throws an exception it will store
the exception into the future (where it can be rethrown at the consuming
site) instead of terminating.  (Thread-based futures work the same way.)
_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
https://lists.boost.org/mailman/listinfo.cgi/boost-users