Boost logo

Boost :

From: Hillel Y. Sims (hys420_at_[hidden])
Date: 2001-08-04 23:51:40


OpenVMS 7.3 (and earlier) uses (VMS) exceptions to implement pthread exit
and cancellation. These system exceptions are catchable by "catch (...)".
For this reason (and the fact that other types of events intercepted by
catch (...) include system exceptions such as accvios, various arithmetic
traps, etc.), we mandate that all code in our multi-threaded environment
that does catch (...) must refrain from doing much more processing than
freing resources and must always "throw;" to reraise the exception, so
that it can be properly handled by the threads system (or a stack trace
printed if an accvio occurred, etc). I don't imagine it's really ever
valid for any code, except maybe absolute outermost-level error handling
routines, to catch (...) w/o reraising the exception untouched --
certainly not library code of any nature. I would be disappointed to see
one of our developers writing a catch (...) block w/o rethrowing, and I
would be disappointed to find that any third-party code I wanted to use
was using catch (...) blocks that did any kind of non-trivial processing
and/or did not rethrow the exception.

It seems to me that something like:
  try {
       // ...
  }
  catch (...) {
     LogError();
     exit();
  }
should only ever appear at the outermost layer of a program anyway,
probably in main() or something close to that. It does not make sense to
me that this would appear anywhere else in a well-design application or
library. There really should not be much of any processing inside a catch
(...) block (except at the outermost layer) other than to simply release
resources and exit cleanly and quickly, and hope that an outer layer
handler knows what to do with this exception.

Although it does have its quirks too, I guess if a thread is going to be
forced to exit, it sort of makes sense to me to use an exception which
invokes the standard stack-unwinding mechanism. What other more controlled
way can there be of forcing the issue? What I would specifically recommend
though, is to specifically _not_ inherit the thread-exit exception type
from std::exception, since this actually represents a sort of system-level
exception vs a strict C++ exception that fits under the hierarchy defined
by std::exception. This allows developers to define their entire
application exception hierarchy in terms of std::exception (as they
probably should be doing anyhow), so that it is possible and valid to use
"catch (const std::exception&)" as the strictest method to catch (and
possibly swallow, though that is not really valid in most cases either)
all C++-based exceptions, while not filtering out any unstoppable
system-exceptions (including thread-shutdown) via catch (...).

As far as #2, the potential drawback due to "void foo() throw() { bar();
}", it seems there is a general debate amongst the experts even about the
overall usefulness of the exception-specification mechanism, so this may
or may not be a very relevant issue going forward.

I think the problem of rethrowing an exception from inside a handler and
invoking terminate() can perhaps be answered in two parts. First, this is
really a more general issue that could exist for many circumstances other
than just thread-exit inside a catch (...) block (eg, we're catching an
accvio exception, and our middle-layer handler code tries to do something
non-trivial that throws another accvio, oh well!). In addition, at least
for pthreads, there is a well-defined and limited set of cancellation
points at which it is possible for a thread-cancel exception to be raised
(unless you turn on asynchronous cancellation, but that's going to
extremes). These include condvar waits, explicit tests for cancellation,
as well as many of the non-trivial system library calls (such as printf, I
think). This means that under this scheme it is possible to write
completely safe exception-handler code for catch (...) without having to
worry about a thread-cancellation exception popping up while inside that
block (as long as the handler code is only doing simple things like
releasing resources, and does not invoke any pthread cancellation points).
I don't know much about the details of Windows threading, as to whether it
has similar cancellation semantics or not?

If the thread-shutdown exception types are defined outside the main
std::exception hierarchy, and it is possible to guarantee synchronous
cancellation points on all platforms, then I think the standard exception
mechanism can provide the full functionality required without requiring a
core language modification. It is possible in poorly-written code for the
end-user to muck up the thread shutdown process by interfering with catch
(...), but a lot of bad things are possible in poorly-written code.

Bababooey to y'all,
hys

-----

Message: 9
   Date: Fri, 03 Aug 2001 19:52:09 -0000
   From: williamkempf_at_[hidden]
Subject: boost.threads [was RE: Re: sockets /network programming
Requirements]

--- In boost_at_y..., williamkempf_at_h... wrote:
> --- In boost_at_y..., "Alexander Terekhov" <terekhov_at_d...> wrote:
> > but then his code would never call thread::exit so there
> > will be no problems. also, IMHO catch(...) without "throw;"
> > or program termination is inherently flawed (e.g. who is
> > supposed to delete the object thrown by not so smart pointer,
> > etc) so i do not see any good reasons not to provide
> > exception based thread::exit even w/o catch(...)
> > workarounds.
>
> Did you totally miss the point about LogError()? *ANY* processing
> done within the catch(...) block is probably not wanted when the
> exception is of type boost_thread_exit_dont_catch_me(). Using
> exceptions is only going to lead to what is viewed as bugs, and
bugs
> that can't be worked around. I won't use such a system, and I'll
bet
> most others won't as well.

In case I've not convinced you yet, here are two other core language
issues with this approach.

1) If while processing an exception a local is destroyed whose
destructor throws an exception, terminate will be called. (15.2/3)

2) Consider the following: void foo() throw() { bar(); }.

What's needed is exception style stack unwinding with no possiblity
of the user circumventing things. To truly get this in a portable
manner that covers all the bases is likely going to require a core
language change and compiler support. This is precisely one of the
reasons why we need a "designed from the ground up" C++ solution
instead of a simple wrapper around POSIX or Win32 threads. We're
doing the best we can to give a library implementation of such a
design, which hopefully can be used for some today, noting any holes
that exist because of changes needed to the C++ abstract machine. If
a concept (like this one) can't be done in the library, we're
removing it with the hopes that it can be added again if/when it's
adopted into the language standard.

Bill Kempf

__________________________________________________
Do You Yahoo!?
Make international calls for as low as $.04/minute with Yahoo! Messenger
http://phonecard.yahoo.com/


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