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

Mark Mitchell mark at codesourcery.com
Mon Jul 11 21:36:22 BST 2005


Jason Merrill wrote:
> Previous discussion on this topic ended in something of a stalemate.

Thank you for re-starting the discussion.  I wasn't happy with the 
stalemate, but I didn't have the fortitude to try again!

> In previous discussions, my favored solution was:
> 1a) Cancellation is disabled during stack unwinding, to avoid trying to
> throw out of a destructor.
> 1b) Make cancellation a normal exception that can be caught and discarded,
> but have the destructor for the exception re-assert cancellation so that
> the process will begin again at the next cancellation point.

I think this is a reasonable solution.

I think I'd still prefer just to have the handler catch the exception 
and discard it, but not strongly enough to try to stand in the way of 
progress.  If you can build consensus around this option, I'll support 
it fully.

Both your model, and the variant I suggest, preserve the pleasant 
property that code which already handles "random" exceptions (like that 
in libraries designed to plug into applications) continues to behave 
reasonably well in the presence of cancellation.

Code that doesn't handle random exceptions probably doesn't handle 
thread-cancellation either; if it's relying on certain functions 
throwing only certain exceptions, then it's probably written to work in 
a relatively controlled environment.  (Of course, if it were compiled 
with headers that say that cancellation point functions throw no 
exceptions, then it would be completely hosed, under any of these models.)

> Then there's the Ada-equivalent model:
> 2a) Cancellation is disabled during destructors and empty exception specs.
> 2b) Cancellation exceptions are not caught by (...).

I think this ought to be considered a non-starter.  Ignoring "catch 
(...)" blocks in C++ is worse than just killing the thread.  Style 
considerations aside, there's a ton of code that relies on that to clean 
up resources, or to otherwise restore state; and running destructors 
after skipping "catch (...)" blocks is just plain wrong, in my opinion.

Maybe in workstation/server applications this makes sense to some 
people, but I don't think it makes any sense at all on an embedded 
system, where the system is often set up to handle complete process 
death, but not weird inconsistencies.  You'd be breaking people's 
program verification regimes, as well.

> Thread robustness (catch and retry).  A thread could have a catch (...)
>   at the top level to try to recover from errors, on the principle that
>   limping along is better than total failure.  Previous discussion seemed
>   to assume that the users would want this to catch cancellation as well,
>   but I think that's wrong; if someone specifically told the thread to go
>   away, they don't want it to recover, they want it to go away.  

I agree.  In fact, despite my oft-stated opinion that it should be 
possible to catch cancellation exceptions, I agree that actually doing 
that -- and never restarting the cancellation process -- would generally 
be a bug in user code.

The reason I'm OK with catching the exception is to do things like:

   try { ... } catch (Cancellation) {
     cancelled = 1;
   }
   /* Other stuff here.  We have no finally clauses in C++.  */
   if (cancelled) {
     throw Cancellation;  // Or, maybe a different exception type, that
                          // tells the top level to cancel the thread.
   }

Your auto-recancel semantics are probably good enough in this kind of 
situation.

> Ulrich Drepper insists that #1 is impossible, because pthread cancellation
> is an irreversible state change.  But I'm not sure why you can't just flip
> various flags back to where they were before.

Yes, I've asked Ulrich about this several times, and have never gotten 
an explanation.

> My current inclination is to go with model #2; backwards compatibility
> with code written to work with pthread_cleanup_push/pop seems like a
> powerful argument in its favor.  People who want model #1 can use a
> different threading library, such as Boost.Threads.

Oh, no...  I thought up until this paragraph that we were going to be on 
the same page.

I think that if #1 really is impossible, #2 might be second-best.  But, 
I'd very much like an explanation of why #1 is impossible.  While I have 
very high confidence in Ulrich's technical abilities, I don't think we 
should have to take his opinions on faith.

-- 
Mark Mitchell
CodeSourcery, LLC
mark at codesourcery.com
(916) 791-8304




More information about the cpp-threads mailing list