|
Boost : |
From: Lee Brown (lee_at_[hidden])
Date: 2002-01-17 04:32:00
>Are you proposing that cancel_push, cancel_pop, goto statements with
>explicit cleanups, and a ban on objects with destructors on the stack is
>more handsome and convenient than using exceptions**, or have I misread you?
I don't know if I was clear or not. (BTW: errno IS thread specific) But your
statements made me do my homework and search the web for the "right" answer.
In short, the issue is confused and Beman was right when he said..
>AFAIK, however, the current Boost.Threads does not require changes to
>current C++ compilers which already support native platform threads.
>That makes it a MUCH easier to sell to the compiler vendors, who are well
>represented on the committee. They can see that it already works, and
>already works with their compiler. It also means users can benefit today,
>rather than having to wait for years.
>--Beman
Here is what the most involved think.
from http://www.lambdacs.com/cpt/FAQ.html#Q280
Q280: C++ exceptions in a POSIX multithreaded application?
...
The questions are:
- What exception is the cancellation request turned into in the target thread?
What is the exception's type? What header should it be defined in?
- Upon catching the exception, what steps does the target thread take to
terminate itself? Just re-enter the threads code by calling pthread_exit()?
- Are the handlers for unhandled and unexpected exceptions global or
thread specific?
- Do unhandled cancellation exceptions terminate the entire process?
- By what interface does the process arrange for cancellations to turn into
C++ exceptions?
- What is the interaction between POSIX cleanup handlers and exception
handling? Do the handlers get executed first and then exception processing
takes place? Or are they somehow nested together?
- Does POSIX cleanup handling play any role in converting cancellation
to a C++ exception?
----------------------------
Here are some answers from the expert.
from: http://sources.redhat.com/ml/libc-alpha/1999-08/msg00038.html
FWD: Dave Butenhof (author of Programming with POSIX Threads) on C++ and
pthread_cancel()
To: gcc_at_[hidden], libc-alpha_at_sourceware.cygnus.comSubject: FWD: Dave
Butenhof (author of Programming with POSIX Threads) on C++ and
pthread_cancel()From: "George T. Talbot" <george_at_[hidden]>Date: Thu, 19 Aug
1999 11:37:08 -0400CC: Ulrich Drepper <drepper_at_[hidden]>, Dave Butenhof
<David.Butenhof_at_[hidden]>, george_at_moberg.comOrganization: Moberg Research,
Inc.
I've got this book called "Programming with POSIX Threads" by Dave
Butenhof. It's really good, so I thought I'd run the whole thread
cancellation issue past him. I asked him if it would be OK to forward
his reply to the lists, and he said it was OK, so here it is...
-- George T. Talbot <george_at_[hidden]> P.S. From what I can glean from replies on the list, the current thread-safe exception model in GCC does not use setjmp()/longjmp() and doesn't have runtime cost for declaring an exception scope. -------- Original Message -------- Subject: Re: Question about your book... Date: Wed, 18 Aug 1999 13:59:48 -0400 From: Dave Butenhof <David.Butenhof_at_[hidden]> Organization: Compaq Computer Corporation To: "George T. Talbot" <george_at_[hidden]> References: <XFMail.990603144303.george_at_[hidden]> <3758014E.51BFC7C3_at_[hidden]> <37BADDE2.205C9974_at_[hidden]> "George T. Talbot" wrote: > Dear Mr. Butenhof, > > I've contacted you before on the issue of thread cancellation and C++, > and I have another question, if you don't mind. > > I've been revisiting thread cancellation and C++ on Linux. What is the > correct behaviour for C++ when a thread is cancelled? I.E. In an ideal > world what effect on C++ code should pthread_cancel() in deferred > cancellation mode have? > > 1) Run all the destructors for objects on the stack and all code in the > catch (...) handlers? > 2) Run all the destructors for objects on the stack? > 3) Nothing? > 4) Segfault? ;^) Yes, in an ideal world, all actions would segfault. That would make coding and debugging easy. (Write anything. It segfaults. Good; it was supposed to. Done with that. On to the next project. ;-) ) MY ideal behavior, and the one towards which I'm working on Tru64 UNIX, is, more or less, your "1". Actually, "1" is what happens with the current OS and C++ release. We're working on moving beyond that to make cancellation (and other system/thread exceptions) known C++ exception classes so that you could write something like "catch(POSIX_cancel) {}" instead of anonymously catching all exceptions. I know others, though, who believe that cancellation shouldn't be catch-able (anonymously or otherwise), and should only run destructors. That's your "2". I don't know of anyone who believes that cancellation shouldn't be required to run destructors. (And if there are any, they're wrong.) Although I don't agree with the idea of "hiding" cancellation exceptions, at least "2" would allow writing cancel-safe code. So I'd have to say that 1 is "near-ideal" (but not as good as making cancel a real C++ exception), 2 is "acceptable". The others are not. > Right now, pthreads under Linux does 3. I've been fooling around with > the implementation, and if I recompile the C library with exception > support (-fexceptions), and have pthread_cancel() do a throw as its last > action after running the cancellation handlers, I can get it to do 1). Interleaved C++ destructors and POSIX cleanup handlers should be run in proper nested order, from inner to outer, in one pass. (They're not "cancellation handlers", by the way, because they're also run by thread exit, and should be run any time an exception propagates through the code scope.) I don't believe it's acceptable to run all cleanup handlers first, then all destructors... or vice versa. Ideally, both are implemented as exception handlers, and the exception propagates normally as one would expect an exception to propagate. One option, when you're using just C++, is to have pthread_cleanup_push() to expand to a block containing a local object with a destructor. The pthread_cleanup_pop() macro would expand to terminate the block. Exiting the scope would then run the object destructor. On normal exit, it would check the pop argument to determine whether to call the cleanup handler; otherwise it'd always call the handler. But that won't help if you have interleaved C and C++ code, unless both languages support a common exception model. That's what we do on Tru64 UNIX, because the underlying common calling standard supports exceptions, and the C compiler provides extensions to declare essentially try/catch scopes. > However the maintainer of the GNU C library won't enable exception > support in the main-line version, as he says it slows down the library > by about 5%. Also, it's been really obvious that the maintainer and > others working on the C library and gcc don't like C++, so I'm kind-of > on my own with this. I don't know what this -fexceptions option does on Linux, but it sounds like it's NOT real exceptions. Maybe something based on setjmp/longjmp. Real exceptions don't have performance overhead (except indirectly via a small increase in object size) until an exception is raised. Exception scopes should be PC mapped, so there's no runtime cost to declare a scope; when an exception is raised, the common exception library can walk the stack and check for exception code ranges to do the proper unwind actions. Too bad. Any system without well-defined "native" exception support is going to have a hard time doing C++ (or Ada, or Modula-2+) at all well. Exceptions need to be free (or very nearly free) until you actually raise one. > I'm hoping that I can figure out a way to unwind the stack and call > destructors, which I might be able to get into a patch, but I'm not > clear on the correct behaviour. You need to be able to unwind the thread's stack one frame at a time, and detect a C++ catch, destructor, or cleanup handler (or any combination) in each frame. Then activate that handler, then unwind to the next frame, and so forth. If you can do a stack walk, you're halfway there; you just need to be able to identify both the C++ and cleanup information. Without real exceptions, most likely the C runtime has some list of setjmp blocks, and the thread library has its own list of setjmp blocks. You'd need to be able to find both lists, and traverse them both to find all the blocks for each frame as you walk the stack. > Thanks for your time. Sorry if I'm adding to an overly full mailbox. That's OK. Good luck! /---------------------------[ Dave Butenhof ]--------------------------\ | Compaq Computer Corporation David.Butenhof_at_[hidden] | | 110 Spit Brook Rd ZKO2-3/Q18 http://members.aol.com/drbutenhof | | Nashua NH 03062-2698 http://www.awl.com/cseng/titles/0-201-63392-2/ |
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk