Boost logo

Boost :

From: Eric Woodruff (Eric.Woodruff_at_[hidden])
Date: 2002-08-24 11:13:07


"> q19) In reality why wouldn't q5's technique for handling an uncaught
exception thrown in a nonjoinable t apply equally well to handling an
uncaught exception thrown in a joinable t as well? (Why have two techniques
instead of one?)<

To support threads that are able to return a value."

The threads can support return values without exceptions, they are
orthogonal, but necessary, concepts.

There still seems to be some question about the default policies:
thread<void> terminates on exceptions by default. thread<void,
throws_exceptions> and thread<void, wraps_exceptions<int,
std::invalid_argument> > may or may not terminate when exceptions are caught
(...) because they were not thrown via boost::throw_exception or not listed
(explicitly) in the wraps_exceptions policy respectively. Personally, I see
it as a debug versus runtime issue -- std::bad_exception would be thrown to
express programmer error during debugging.

In Dan'l's list of questions, I don't know if it the fact that parallel
calls to join () will all have exceptions propagated to them.

----- Original Message -----
From: Peter Dimov
Newsgroups: gmane.comp.lib.boost.devel
Sent: Saturday, 2002:August:24 11:30
Subject: Re: Boost.threads: interthread exception conveyance

From: "Dan'l Miller" <optikos_at_[hidden]>
>
> As the tumult was going on, I was reading the multitude of recent
"Threads & Exceptions Issue" postings.
>
> Although much debate occurred with many back-and-forth discussions, I
never saw a clear & concise conclusion stating "Boost.threads shall do this"
and "Boost.threads shall not do that" design decisions. Because those
tumultuous threads have faded out, I assume that the topic has been
discussed to the Boost community's satisfaction and that a complete set of
conclusions was reached. I am interested in what the conclusions to the
following topics were:<

There were no definitive conclusions. I can answer the questions under one
of the proposed models.

> q1) Is Boost.threads going to pursue any kind of conveyance of an
exception thrown and not caught on a thread t back to the thread s which
started t (i.e., conveyance as an exception-type instance, not expressed as
an instance of a return type)?<

Let's assume that the answer is "yes".

> q2) If q1 is yes, in which circumstances? (e.g., in the case that s
started t via a non-void template-parameter for the return-type concept)<

Non-void return type.

> q3) If the criterion in q2 which precipitates conveyance of an uncaught
exception on t is in fact a non-void template-parameter for the return-type
concept, would t be joinable (as a chronologically-oriented boolean
condition) if the return-type were void? (I suspect not, even though this
occurs in existing MT practice.)<

Yes, the thread is joinable. The return type of join is void.

> q4) If in q3 a void return-typed t is still joinable, what is to happen
to t's uncaught exceptions?<

Terminate the process (except thread_cancel, which is silently ignored.)

> q5) If in q3 a void return-typed t is not still joinable (i.e., t is a
detached thread whose lifetime semantics are either 5a) run until
end-of-process or 5b) run until t decides to end its own life), what is to
happen to the nonjoinable t's uncaught exceptions?<

Terminate the process.

> q6) Is a void return-typed t the only way to create a detached thread
which is not to be joined? If not, compare & contrast a void return-typed t
semantics with a detached-the-other-way t<sub>1</sub><

All threads can be joined (if you have access to a reference to the thread.)

> q7) For a detached t which by app-domain design is not to be joined, if
t has an uncaught exception and if q1 is yes, does the detached-by-design t
still convey the exception back to s?<

A non-void return R implies intent to call "R join()" to obtain the thread
function return value. Threads that are not to be joined should not use
non-void returns.

> q8) If q1 is yes, exactly which type is thrown in s (e.g., the same type
as in t; all exception types thrown and not caught in t conflate to a single
exception type in s)?<

Unspecified. A perfect implementation would rethrow the exception as-is.

> q9) If in q8 t's uncaught exception-type type is (re)thrown in s,
exactly how would the exception be conveyed from t to s? E.g., if t's
uncaught exception itself is the instance to be conveyed to s, then how
would Boost.threads ensure that unwinding t's stack does not destroy t's
exception instance.<

Unspecified.

> q10) If in q8 t's uncaught exception-type is (re)thrown in s but a new
instance of t's uncaught exception-type is instantiated for s as part of the
mechanism of how the interthread exception conveyance is accomplished, how
does t convey that most-fully-derived type information to s? (Having merely
a reference to ::std::exception in t does not tell anything about how to
invoke a copy-ctor for the most-fully-derived type.)<

Unspecified.

> q11) If q1 is yes, at which point would the interthread
exception-conveyance from t ingress s? E.g., any old place; at the
thread-join-with-t point; at a set of specially-picked standard C++ library
invocations.<

"R join()" throws an exception.

> q12) If q1 is yes and q11 is the thread-join-with-t-point in s and if
(re)throwing t's exception-type instance (uncopied) in s is the intended
interthread exception-instance conveyance mechanism, how is t's
exception-type instance preserved for (possibly long) periods of time until
s reaches the join point because t might have thrown before (and maybe quite
a long time before) s reaches its join-point with t?<

Unspecified.

> s13) If q1 is yes and q11 is the thread-join-with-t-point in s, then let
us consider a still more troublesome case where s did not merely start a
single thread t, but also n other threads too which are all to be joined
back to s at a thread-join-with-T-point. In this case s started n+1
threads: T={t, t1, t2, ..., tn}. Let us consider the case where two or more

threads in T experience trouble which is out of their league and thus two or
more threads in T have uncaught exceptions which by q1 s would need to
handle and by q11 would ingress s at the thread-join-with-T-point.<

There is no join-with-set operation.

[...]

> q17) If scenario s13 cannot occur due to the lack of a single n+1-ary
thread-join-with-T-point abstraction but rather only a n+1-member ordered
set J of {thread-join-with-t-point, thread-join-with-t1-point, ...,
thread-join-with-tn-point} whose members occur serially in s, and if {t, t7,
t9} throw exceptions, s's stack unwinds when t's exception is conveyed
(chronologically first due to first join), but then what happens to t7's
uncaught exception and t9's uncaught exception? E.g., silent t7 & t9 thread
exit but not process exit; process exit; t7's exception & t'9 exception
shall be handled a different way than conveyance to s.<

Silent t7 & t9 thread exit. More precisely: the lifetimes of t, t7 and t9
have already ended. t.join(), t7.join(), t9.join() will throw an exception.
If t7.join() is never invoked, it will never throw.

[...]

> q19) In reality why wouldn't q5's technique for handling an uncaught
exception thrown in a nonjoinable t apply equally well to handling an
uncaught exception thrown in a joinable t as well? (Why have two techniques
instead of one?)<

To support threads that are able to return a value.

_______________________________________________
Unsubscribe & other changes:
http://lists.boost.org/mailman/listinfo.cgi/boost


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