|
Boost : |
From: William E. Kempf (williamkempf_at_[hidden])
Date: 2002-08-13 09:52:11
----- Original Message -----
From: "Darryl Green" <green_at_[hidden]>
> Lets try to deal with this using terminate instead: I need to handle the
> termination of the library thread and the fact that that library has
become
> unuseable by bringing the app as a whole to a civilised halt in an app
(not
> lib) dependent way. It is not clear to me what state "my" threads will be
in
> at the time terminate() is called as a consequence of an unhandled
exception
> in another thread - if I can assume that no stacks have been unwound
except
> (possibly) the thread that threw, I guess I can recover in a terminate
> handler - though its going to be hard because I (assume) the handler is
> running in the context of a thread I didn't create. I'm going to have to
> somehow synchronise with and transfer control to thread(s) I do control.
I'm
> going to have to do a join() so that my terminate handler won't return.
Does
> this sound like a good thing? Is relying on these undefined behaviours a
> good thing (or are they somehow defined)? Have you proposed a better way?
The point that the terminate_handler will run in the context of the failing
thread is a good point. The most convincing one made yet. Compelling
enough that you may have just changed my mind, though I'm still unhappy
about some of the details. Let me outline what I'm thinking now.
The terminate() semantics are still useful, and I think appropriate for
several reasons, but the semantics have to be modified to prevent
asynchronous application termination. This means terminate_thread()
instead, which only terminates the current thread and not the application.
A set_terminate_thread_handler() can be employed to handle this case in the
same manner that you'd use for application termination. (Question... should
this be callable from the thread object, allowing other threads to set the
handler, or should this be a static/global method that effects only the
current thread?) One thing this terminate_thread() does is to handle the
propogation of exceptions by setting the appropriate state information in
the shared thread data (sorry, I'm revealing to much of the implementation
details here, but it's the only way I can think of to describe what
happens). Any calls to any of the thread methods will poll for this, and
throw the appropriate exception if found. (Question... is a generic
thread_terminated exception acceptable, or do we need to complicate the
implementation with propogating the uncaught exception?)
The details I'm unhappy about...
1) I have to treat main() differently here. Unless someone else sees
something I don't, I can't see how to portably provide the same semantics to
the main thread.
2) Shared resources are likely to be in an inconsistent state, so there's
not really any way to recover here... you only have the ability to terminate
gracefully. That's still significant, and is probably better than the
alternative, but still an issue users have to be aware of.
3) Problems can still be progressively worsened if the user doesn't properly
deal with the exceptions and relies solely on propogation, since shared
resources can be compromised long before you poll for termination. Worse
still, polling can't be employed at any point prior to join() in any useful
manner, as it will only result in a race condition. (Is this an argument
that only join() should throw, contrary to what I said above?)
1 is the worst, while 2 & 3 can be handled by careful documentation of the
issues and programmers being vigilant... though they still make exception
handling even more difficult than it already is. I guess I'm thinking we're
going to have to live with all of these issues, but I'd still like further
talk about them.
Bill Kempf
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk