
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
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