Re: [cpp-threads] pthread_cancel and EH: let's try this again
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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



Some comments...

Jason Merrill wrote:

[...]

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.
Apparently this is also the Boost.Threads design.

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

And the current status quo in GCC:
3) #1, except that the destructor for the exception calls abort().
Additional inelegant possibilities for the destructor would be
killing just the thread, throwing a new exception, or doing nothing
(leaving the thread in a sort of zombie state).

1. Boost.Threads doesn't support cancellation. Very possibly never will.

2. The arguments in favor of ... not catching the cancellation exception can be summarized as:

2a. We can break perfectly valid catch(...)+rethrow cleanup code because it's inelegant.

2b. Some people that use catch(...) don't really want catch(...) semantics.

3. Non-empty exception specifications may terminate() on cancellation. (These are even less elegant than catch+rethrow, of course.)

This is also true in cases where the original code avoided terminate() by remapping exceptions:

void f() throw( MyException )
{
   try
   {
       g();
   }
   catch( MyException const & )
   {
       throw;
   }
   catch( ... )
   {
       throw MyBadException();
   }
}

(Remapping via unexpected() will work, though, if the cancellation exception plays by the rules.)

4. Inter-language communication is usually done by translating the exception into a return code, squeezing that through an extern "C" interface, then optionally throwing at the other end. It isn't just catch and rethrow something else.

5. Disabling cancellation during empty exception specs is too coarse:

int f() throw()
{
   try
   {
       return lengthy_operation();
   }
   catch(...)
   {
       return EXCEPTION;
   }
}

I want cancellation to be active during lengthy_operation.

Summary:

I'm in favor of 1 minus the "destructor reasserts" part (it's not needed). I'm undecided on whether the cancellation request is (implicitly) cleared when the cancellation exception is thrown. There are good arguments in favor of either approach, and a reasonable compromise would be to not clear the cancellation request and provide a function for clearing it explicitly for the cases where this is desired.

Finally,

People who want model #1 can use a different threading library, such as
Boost.Threads.

this is impossible on a number of levels. :-)