asio: transporting exceptions across threads
Suppose I have some io_service object in which I call run() from thread A. Thread A is the main controller of the i/o operations and does things like issuing reads and, upon completion, issuing writes for those reads. The writing service might wish to spawn off some child services that runs in thread B. So when thread A says writer.async_write_data() all it really does is call child_writer_service.post() with the data. Supposing an exception occurs in thread B, what is the best way to have this terminate the entire asio pipeline and propagate the exception all the way up to outside of thread A's call to io_service::run()? I've looked at the sample code on the boost::exception tutorial but I'm unable to apply this to the situation in asio, either due to differences in the threading model or due to my own misunderstandings. Thanks
I have never used boost::asio but a complete example of how to use
boost::exception_ptr can be found here (see Cloning and Re-Throwing an
Exception) :
http://www.boost.org/doc/libs/release/libs/exception/doc/tutorial_exception_...
Let me know if this works for you.
Emil Dotchevski
Reverge Studios, Inc.
http://www.revergestudios.com/reblog/index.php?n=ReCode
On Tue, Jul 21, 2009 at 11:00 AM, Zachary Turner
Suppose I have some io_service object in which I call run() from thread A. Thread A is the main controller of the i/o operations and does things like issuing reads and, upon completion, issuing writes for those reads. The writing service might wish to spawn off some child services that runs in thread B. So when thread A says writer.async_write_data() all it really does is call child_writer_service.post() with the data.
Supposing an exception occurs in thread B, what is the best way to have this terminate the entire asio pipeline and propagate the exception all the way up to outside of thread A's call to io_service::run()?
I've looked at the sample code on the boost::exception tutorial but I'm unable to apply this to the situation in asio, either due to differences in the threading model or due to my own misunderstandings.
Thanks _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Tue, Jul 21, 2009 at 3:38 PM, Emil
Dotchevski
I have never used boost::asio but a complete example of how to use boost::exception_ptr can be found here (see Cloning and Re-Throwing an Exception) :
http://www.boost.org/doc/libs/release/libs/exception/doc/tutorial_exception_...
Let me know if this works for you.
Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
Yea that was the code I was referring to when I was saying I'd looked over the tutorial code in the docs. The problem is that it's difficult to explain what the problem is. Essentially I have N threads. 1 of these we can consider the "master" thread, which is also the main application thread. The other threads are all worker threads in some form or another. In order to "start" asio, you at some point run this function which is essentially an event loop that doesn't return until it runs out of work to do, or until an exception propagates outside of the event loop. The model in place is that you run this event loop in each thread that is supposed to participate in asio. So, with the exception of the main application thread, I've created all of these worker threads with a very simple thread start routine function that all it does is run the event loop. In the example in the documentation, it relies on the fact that there is a well-defined sequence point at which the main thread can call thread::join on the child thread. But this doesn't really happen in asio. Nothing in the parent thread's handlers or worker code has any idea that other threads are running at all. I can let the exception propagate all the way out of my worker thread's event loop and have the thread function just return, but then the parent thread hangs because it posts a message to this service and the service just doesn't respond. It's also not clear how such error handling will play well with the fact that there's many different threads running. For example, I encounter the error in worker thread B, and thread A is trying to post a message to thread B at the same time. If I simply shut thread B's service down when I encounter the error, is this goign to exhibit well-defined behavior? I've thought of a couple of possible ideas, but all of them seem hackish and I'm not sure how well they'll scale. Some of them I've tried, but then asio encounters weird issues in the destructor of one of its internal classes called service_registry. Was hoping someone had encountered this before and come up with something.
Right, the model that fits exception_ptr better is when you have a thread working on a result which another (main) thread receives; so the main thread would either get a valid result from a working thread, or an exception_ptr that describes the reason why the result couldn't be computed.
From your description (keep in mind I've never used boost::asio) it seems that what would work better in your case is to incorporate exception_ptr into a message of some sort, since it seems like the worker threads in your case are just parts of a bigger, coherent system (as opposed to working on individual tasks.)
What should happen when an exception occurs? Should the thread it
occurred in be terminated, or should it simply report the problem and
continue working on something else? What kind of errors are we talking
about? If the user should be notified, perhaps you can create a queue
for worker threads to push exception_ptr objects into, while another
thread pops them from the other side and formats user-friendly
messages?
I'm sure this is perfectly clear to you already, but basically all
that exception_ptr gives you is the ability to hold on to an exception
object as long as you need to, so you can either exit or "keep going"
in the thread where the exception occurred, handing the exception_ptr
to another thread to re-throw it (and use an appropriate catch to deal
with it.)
Emil Dotchevski
Reverge Studios, Inc.
http://www.revergestudios.com/reblog/index.php?n=ReCode
On Tue, Jul 21, 2009 at 2:16 PM, Zachary Turner
On Tue, Jul 21, 2009 at 3:38 PM, Emil Dotchevski
wrote: I have never used boost::asio but a complete example of how to use boost::exception_ptr can be found here (see Cloning and Re-Throwing an Exception) :
http://www.boost.org/doc/libs/release/libs/exception/doc/tutorial_exception_...
Let me know if this works for you.
Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
Yea that was the code I was referring to when I was saying I'd looked over the tutorial code in the docs. The problem is that it's difficult to explain what the problem is.
Essentially I have N threads. 1 of these we can consider the "master" thread, which is also the main application thread. The other threads are all worker threads in some form or another. In order to "start" asio, you at some point run this function which is essentially an event loop that doesn't return until it runs out of work to do, or until an exception propagates outside of the event loop.
The model in place is that you run this event loop in each thread that is supposed to participate in asio. So, with the exception of the main application thread, I've created all of these worker threads with a very simple thread start routine function that all it does is run the event loop.
In the example in the documentation, it relies on the fact that there is a well-defined sequence point at which the main thread can call thread::join on the child thread. But this doesn't really happen in asio. Nothing in the parent thread's handlers or worker code has any idea that other threads are running at all. I can let the exception propagate all the way out of my worker thread's event loop and have the thread function just return, but then the parent thread hangs because it posts a message to this service and the service just doesn't respond.
It's also not clear how such error handling will play well with the fact that there's many different threads running. For example, I encounter the error in worker thread B, and thread A is trying to post a message to thread B at the same time. If I simply shut thread B's service down when I encounter the error, is this goign to exhibit well-defined behavior?
I've thought of a couple of possible ideas, but all of them seem hackish and I'm not sure how well they'll scale. Some of them I've tried, but then asio encounters weird issues in the destructor of one of its internal classes called service_registry.
Was hoping someone had encountered this before and come up with something. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (2)
-
Emil Dotchevski
-
Zachary Turner