[c++-pthreads] Restating the Jason model

Dave Butenhof David.Butenhof at hp.com
Tue Jan 13 13:31:51 UTC 2004


Wil Evers wrote:

> Jason Merrill wrote:
>
>> I think this is an appropriate time to restate my proposal.  I think
>> there's a fair amount of consensus around these three points:
>>
>>  * Cancellation is a normal exception.
>>  * If a cancellation exception is destroyed, the cancellation request
>>    is re-entered, and acted on again at the next cancellation point.
>
> I can't help wondering about the difference between this design and 
> Nathan's sticky cancellation model.  It seems to me that in your 
> model, I can do something like:
>
>   catch (const cancellation_request&) {
>     some_socket.write("Thread cancelled\n");
>   }
>
> and expect the write operation to succeed, whereas in Nathan's sticky 
> cancellation design, the write operation will throw another 
> cancellation_request (unless, of course, I disable cancellation in the 
> catch block).  If so, is this intentional?

Absolutely; because the correct behavior of the application (which might 
be distributed) could depend on being able to notify the remote partner 
that the local thread is shutting down. Nathan's proposal doesn't allow 
that, and that's the big weakness.

Jason's proposal will cause the cancel to be re-asserted when the 
exception object is destroyed, on exit from the catch(), after local 
cleanup has been done. This makes the catch() behave (more or less) like 
a destructor.

> And what about this one:
>
>   try {
>     some_socket.connect("www.ibm.com");
>   } catch (const cancellation_request&) {
>     throw my_fancy_exception(__FILE__, __LINE__,
>       "Cancellation request");
>   }
>
> Here, unwinding continues, but the cancellation request is mapped onto 
> some other - presumably legacy - exception hierarchy.  Do we really 
> want the cancellation request to be re-entered here?

Yes, perhaps; because propagation of my_fancy_exception would either be 
swallowed later (probably, since nobody would have thrown it without a 
catch) or else it'll terminate the process. Neither meets the semantic 
definition of cancellation, or the expectations of the application code 
that sent the cancel.

Of course, you could get arbitrarily convoluted here, my somehow making 
the propagation of my_fancy_exception inherit the "progagating cancel" 
state so that when THAT object is destroyed the original cancel will be 
re-raised, or so detection of THAT unhandled exception will terminate 
the thread rather than the process. (Though I'm not at all convinced 
that's what we'd want to happen.)

One alternative is to simply say that such code is NOT cancel-safe; and 
that the behavior of a thread running such code when cancelled is 
inherently unreliable. A lot of existing code won't be cancel-safe, and 
I don't believe that there's anything the standard or any implementation 
can do about that.

> To me, it seems like Nathan's sticky cancellation model uses a 
> tried-and-tested design - it simply puts the thread object into an 
> error state, causing subsequent operations to fail - whereas your 
> design is quite innovative.  I'm not suggesting there is anything 
> wrong with that, but I do believe it needs to be justified.

There's no such thing, currently, as an error condition that will cause 
ALL subsequent blocking operations to fail. It's not at all "tried and 
tested".

Aside from the "sticky" characteristic, which seems to be an almost 
necessary consequence of the C++ catch(...) syntax and idiom, Jason's 
proposal is exactly the model for which POSIX cancellation was designed, 
and which has been in wide use for up to 12 years. (Starting with our 
CMA library on VMS and ULTRIX, and extending out through POSIX 
standardization to most other UNIX-based systems.)

>>  * Should cancellation also be disabled in destructors run during normal
>>    execution?  In catch blocks?
>>
>> IMO, no and no.
>
> This implies a difference in how destructors behave, depending on why 
> they are invoked.  If such a difference can be avoided, I think it 
> should be: we have Ted Baker's model (destructors always disable 
> cancellation), and the other obvious choice is to leave it to the user 
> to take the necessary precautions when writing destructors. Good C++ 
> programmers already know how to do that.

They may know how, but most haven't previously had any need to worry 
about that. It seems to be fairly widely agreed here that propagating an 
exception out of a destructor is "bad". Since that's what will happen if 
cancellation strikes an unprepared destructor, it seems to me that the 
best option is to prevent that in the default case (by disabling 
cancellation), and requiring any destructor that really WANTS to be 
cancellable to do something unusual.

-- 
/--------------------[ David.Butenhof at hp.com ]--------------------\
| Hewlett-Packard Company       Tru64 UNIX & VMS Thread Architect |
|     My book: http://www.awl.com/cseng/titles/0-201-63392-2/     |
\----[ http://homepage.mac.com/dbutenhof/Threads/Threads.html ]---/




More information about the c++-pthreads mailing list