[c++-pthreads] Re: pthread_cancel and EH: let's try this again
Nathan Myers
ncm at cantrip.org
Sun Jul 17 22:37:48 UTC 2005
It strikes me that Wil Evers has posted the most practical
suggestion I have seen, on this list, since its inception.
On Sun, Jul 17, 2005 at 12:23:45AM +0200, Wil Evers wrote:
>
> ... it seems feasible - or even
> desirable - to use a model in which the cancellation machinery doesn't
> implicitly disable cancellation at all, not even when unwinding the
> stack.
> ...
> cancellation_manager::cancellation_manager(bool enable)
> {
> pthread_setcancelstate(
> enable ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE,
> &saved_state);
> }
> cancellation_manager::~cancellation_manager()
> { pthread_setcancelstate(&saved_state, 0); }
> ...
> (*) It provides a clear migration path for existing multi-threaded C++
> code that was not written to expect cancellation exceptions (see
> above).
>
> (*) It doesn't impose any particular cancellation handling policy,
> leaving it to the programmer to decide when and how to respond to
> cancellation requests.
Like any suggestion, Wil's might benefit from refinements. I hope that
Wil can maintain a summary that may form the basis for a specification.
(Can somebody suggest a Wiki where we might add an appropriate page?)
We have several advantages, in discussing a C++ binding, that those
before us (e.g. those designing C bindings) did not have, and a few
disadvantages. For advantages, (1) we have a much more powerful
language that can express our intent directly; (2) there is no
coherent body of existing practice, so we can proceed sensibly;
and (3) we have much less political bias to skew our choices.
Our disadvantages might be that we are that we are more ambitious
than our predecessors, and that what we choose is less directly
influential. Both of the latter may be turned to our favor: they
force us toward a design that is inherently compelling, leading users
outside our circle to demand that their vendors adopt, and even
standardize, it. We can implement it and deploy it more easily than
most, exposing potential users to our chosen semantics.
(A distinct advantage to us this time around is that no one shrieks
"Zero Uptake! Zero Uptake!" whenever a suggestion arises that is
compatible with Standard C++ semantics.)
We are more ambitious in that we mean to preserve the usefulness,
within threads that might be cancelled, of a much larger body of
existing library code, both in C and in C++, written without
awareness of the possibility of cancellation. We mean to evolve a
design without serious pitfalls for those less experienced with
thread semantics, or who (like most) have never heard of
cancellation.
Here are some goals I hope we can mostly agree on:
1. Existing C libraries that *do* try to take cancellation into account
should still work, where practical. Existing C++ code that relies on
C cancellation behavior should be easy to adapt, presuming it really
worked, before, and not only by accident.
2. Existing thread-safe and exception-safe C and C++ libraries that do
*not* take cancellation into account should still work. (This implies
that C library calls, including system calls, never throw, by default
or during normal operation; likewise for C++ destructors, and C++
functions with any throw specification.)
3. We have no need to preserve existing "thread-main" code without
changes. That code is rarely very portable, and in ported code
routinely has #ifdefs scattered through it already. As much as
possible, the need to know about cancellation should be confined to
thread-main and program-main code.
4. We must not assume that C libraries, in general, can handle
propagating an exception safely (e.g. from a C++ callback), because C
doesn't provide the tools to enable it, POSIX cancellation apparatus
notwithstanding.
5. Thread- and exception-safe libraries that do not deliberately
interact with cancellation machinery should not normally need to be
recompiled. Accommodating possible cancellation events should not
slow down normal code execution.
6. We need make no artificial distinction between "discarding
cancellation" and "indefinitely delaying" thread termination, unless
the distinction becomes helpful.
7. We may assume we can hijack/shadow standard system and library
calls and add our own semantics, such as causing them to report
failure (perhaps with distinguished ERRNO codes) under circumstances
where they would otherwise have succeeded, or (under C cancellation)
entered some sort of cleanup mode. (Scott Lamb has experience in this
area.)
8. A C++ cancellation event need not map to any POSIX C cancellation
construct; any attempt to cancel a thread in a C++ program must be
routed to code with the semantics we choose, independently of whatever
the C runtime would try to impose. If it's useful to initiate a C
cancellation, at some point in the process (perhaps at the end, after
stack unwinding) we might do so.
I'll stop here. Combining Wil's suggestion and mine (in which most
system calls are made to fail) seems to me to solve most of the
problem. What seems to remain is breaking out of long-running
computations that perform no system calls. Adding a distinguished
signal (which handler, like any signal handler, would not be allowed
to throw) might help there.
Nathan Myers
ncm at codesourcery.com
ncm at cantrip.org
More information about the c++-pthreads
mailing list