[c++-pthreads] Re: pthread_cancel and EH: let's try this again

Peter Dimov pdimov at mmltd.net
Thu Jul 21 13:44:47 UTC 2005


Mark Mitchell wrote:

> That means that the most important question we should answer is what
> to do for the program above, when the "throw;" is removed.
>
> I think the only reasonable choices are:
>
> 1) Fall off the end of the catch clause in the usual way, but the
> thread is still cancelled.  Encountering another cancellation point
> will result in re-raising the cancellation exception.
>
> 2) Fall off the end of the catch clause in the usual way, but the
> thread is no longer cancelled.  It can be re-cancelled, but until it
> is, it will operate normally.

A real problem with the straightforward approach (2) is that cancellation 
requests can be lost. The thread that invokes pthread_cancel has no idea 
that the receiving thread has encountered an exception-eating catch block, 
so it doesn't know that it needs to retry the pthread_cancel call.

This problem has motivated several (proposed or real) drastic modifications 
of (2), including banning catch without rethrow via std::terminate, not 
invoking catch(...) blocks at all, or banning catch without rethrow in a 
coding standard and loudly condemning its use in public forums. In my 
opinion, it is much easier and cleaner to just address the actual problem 
instead - deprecating or crippling catch(...) is not within the charter of 
the group. :-) In other words, we need to make sure that cancellation 
requests aren't lost easily.

One additional detail is that under the POSIX rules, cancelability is 
disabled just before "stack unwinding" starts. Not a problem under pure 
POSIX C, because cancellation is impossible to finalize.

A problem under both (1) or (2), though. Even under (1), where cancellation 
is sticky and the request isn't lost, encountering a cancellation point will 
not re-raise a cancellation exception, because cancelability is left 
disabled.

Therefore, a useful model will at least have the following properties:

A. cancellation is sticky, requests aren't lost easily;

B. cancelability is not left disabled after a cancellation exception has 
been finalized.

A simple solution is to adopt (1) and re-enable cancellation at the end of 
the catch clause.

This solution is not without its merits and is actually a workable 
approximation of the "ideal" model, but it has the following problem: the 
proper value of the cancelability state after the exception is finalized may 
be "disabled". In the example below:

// #1

try
{
    f();
}
catch( ... )
{
}

// #2

the cancelability state at #2 ought to be the same as the cancelability 
state at #1, provided that its only explicit manipulation is via a RAII 
guards that always restore it to its previous value.

Remembering the state at the cancellation point doesn't work; it may've been 
asynchronous. It may even have been disabled if the cancellation exception 
originated from an explicit user throw.

All this leads me to propose the following model:

C. the cancelability state only changes if pthread_setcancelstate is invoked 
(deviation from POSIX which resets it at the throw point to 
deferred+disabled);

D. to match POSIX semantics, cancellation points don't throw if there is an 
unfinished exception.

(D) makes no distinction between cancellation exceptions and other 
exceptions for the following reasons:

- every special case introduced into the core language will create more 
problems than it solves;

- the point of cancellation is to initiate stack unwinding, and when an 
exception is active, stack unwinding is already under way;

and

- given std::unfinished_exception(), the semantics of cancellation are also 
implementable in user code or libraries and do not need compiler support.

The last remaining issue is that (2) has one advantage over (1) - it enables 
the user to ignore a cancellation request. There are use cases that can take 
advantage of that - if you are interested I can go into more detail.

But under the model described so far, a cancellation request is a bit too 
sticky; it's impossible to ignore.

To address this, I propose that we provide an explicit API to clear a 
pending cancellation request... or at least specify it in case someone wants 
to revise his opinion on the irreversibility of cancellation. ;-)




More information about the c++-pthreads mailing list