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

Wil Evers wil at bogo.xs4all.nl
Sat Jul 16 22:23:45 UTC 2005


Mark Mitchell wrote:

> Wil Evers wrote:
> 
>> I agree, but please note that the handling of catch (...) blocks is 
>> not the only distinction between model #1 and model #2.
>>
>> In model #2, cancellation is disabled in all destructors; in model #1, 
>> cancellation is only disabled when destructors are called while 
>> unwinding the stack.
>>
>> In other words, #2 has the desirable property that it does not break 
>> existing code that assumes destructors *never* throw. I suspect that a 
>> lot of code relies on that assumption, and I know for sure that 
>> practically all of my code does. 
> 
> Good point.
> 
> However, that seems orthogonal to the other issues; we could certainly 
> have #1 disallow cancellation in all destructors, if we wanted.  

I agree.

> I don't 
> really know how we plan to do that in #2, without inserting additional 
> code in every destructor, which seems unfortunate.

Again, I agree.  IIRC, in the previous round of discussions on this 
mailing list, Jason said he feared the performance impact of having to 
disable cancellation in every destructor.

>> Supposing model #1 is accepted, then how do we cope with existing code 
>> that assumes destructors never throw, or, more generally, with code 
>> that was not written to deal with exceptions thrown from cancellation 
>> points?
> 
> The compiler must know that cancellation points may throw exceptions, as 
> otherwise it may have optimized away exception unwind information, as it 
> would when calling any "nothrow" function.
> 
> However, I realize that you're asking about user code, more than about 
> the compiler.

It seems to me you may have missed the point I was trying to make at the 
end of my previous message, which is that 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.  Please consider this example:

   class cancellation_manager {
   public :
     explicit cancellation_manager(bool enable)
     {
       pthread_setcancelstate(
         enable ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE,
         &saved_state);
     }
     ~cancellation_manager()
     {
       pthread_setcancelstate(&saved_state, 0);
     }
   private :
     cancellation_manager(const cancellation_manager&);
     void operator=(const cancellation_manager&);
     int saved_state;
   };

   void *thread_routine(void *)
   {
     cancellation_manager disabler(false);
     std::ofstream outfile("filename");

     // lots of legacy code...

     outfile << "some output" << std::endl;

     {
       cancellation_manager enabler(true);
       some_cancellation_point();
     }

     // more legacy code...

     return 0;
   }

I believe the code above is immune to the surprises caused by changing 
ordinary system calls into functions that can throw cancellation 
exceptions.  In particular, we can be sure that outfile's destructor 
(which may invoke write() to flush its outbuf buffer) will never throw. 
  This is because the programmer decided to disable cancellation by 
default, and to only enable it for limited sections of code that were 
written with cancellation in mind.

IMO, not having the cancellation machinery implicitly disable 
cancellation has two distinct advantages:

(*) 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.

- Wil



More information about the c++-pthreads mailing list