Boost logo

Boost :

Subject: Re: [boost] [Thread] Win32 exception handling
From: Matt Gruenke (mgruenke_at_[hidden])
Date: 2008-11-26 11:49:19


vicente.botet wrote:
> ----- Original Message -----
> From: "Matt Gruenke"

>> The catch (...) is one of the reasons we don't use boost::thread. I
>> even filed a bug on it:
>>
>>
>> http://sourceforge.net/tracker/index.php?func=detail&aid=1274707&group_id=7586&atid=357586
>>
>
> When I try to open this page anerror apears. Can you post the ticket?
>

That bug tracker is apparently obsolete. As I know of no way to gain
access to my filing, here's the text:

Feature Requests item #1274707, was opened at 2005-08-27 13:10
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=357586&aid=1274707&group_id=7586

Category: thread
Group: None
Status: Open
Resolution: None
Priority: 5
Submitted By: Matthew Gruenke (mgruenke)
Assigned to: William E. Kempf (bill_kempf)
Summary: Remove try/catch(...) in thread.cpp:thread_proxy()

Initial Comment:
THE CASE AGAINST try {} catch (...) {} IN
libs/thread/src/thread.cpp:thread_proxy()

The only platform on which I've used boost::thread is Linux + GCC. So,
on the debugging front, I can only speak to that. In this configuration
(using pthreads), the behavior of an exception being allowed to
propagate outside of a thread function is quite useful - you get a
backtrace of the entire call sequence leading up to the throw, AND a
full unwind back from that point (which looks like further entries in
the call stack). However, if an exception is caught & rethrown, all of
the prior call & unwind history is lost. Obviously, this also happens
if an exception is caught and not rethrown - which is the current (circa
version 1.33.0) behavior of thread_proxy().

I've tried a number of experiments, as well as inspecting pthreads &
glibc code, and have been unsuccessful at reproducing this behavior in
user code. However it's so useful that, on virtually every project
where I'd like to use boost::thread, I eventually resort patching the
source to remove this last-resort try/catch block.

For a library to be of much practical value, debugging must not be
significantly impaired (and even enhanced, where possible without
significant compromises). The additional complexity of multithreaded
programs makes this all the more important. I think this point stands
pretty well, on its own.

A more troubling aspect of this try/catch block is that the thread
terminates in exactly the same way via an otherwise unhandled exception
as it does when the user-supplied threadfunc exits cleanly. If the user
of boost::thread didn't think to catch the particular exception in
question, then it's unlikely it employed and is inspecting any other
mechanism for determining whether the thread accomplished its goal.
This assumption violated, it's unsafe to assume the program will
continue to function correctly.

Since the thread exists in the same memory space as the rest of the
process (and shares library state, if not also other data structures),
an unhandled exception indicates bad state in the process, or some other
invalidated assumption. In fact, in non-exception-safe code, it may
even produce bad state. Any of these conditions makes it unsafe to
assume the program will continue to operate correctly.

Finally, there's a more philosophical point that should probably be
made. The primary purpose of exceptions is to provide proactive
notification of program errors (as opposed to relying on return codes -
which facilitate errors being silently ignored). Why should behavior of
uncaught exceptions in other threads be any different than main? Yet
thread_proxy() just quietly drops them on the floor. As a user, I
normally expect that no unhandled exceptions were thrown, if my program
runs to completion.

WHAT WILL HAPPEN IF IT'S REMOVED?

If the user specifically wants this behavior, it can suitably augment
its user-supplied threadfunc to contain the catchall. There's nothing
wrong with simply stating that the behavior of exceptions that propagate
outside threadfunc is undefined.

While changing this might "break" some existing code, it's really quite
likely that code is already broken - though the user simply doesn't know
it. IMO, there's nothing wrong with libraries evolving to detect more
errors and invalid conditions.

CONCLUSION

In summary, I believe the current behavior is:
  1. Dangerous - hides program errors in a most un-exception-like
                 manner.
  2. Unfriendly - defeats useful debugging functionality,
                  on some platforms.
  3. Surprising - users don't expect libraries to inhibit propagation
                  of their exceptions.
  4. Unnecessary - the user can easily supply this behavior,
                   if desired.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk