Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost



Dave Butenhof <david.butenhof@xxxxxx> writes:

> David Abrahams wrote:
>> Dave Butenhof <david.butenhof@xxxxxx> writes:
>>
>>   
>>> However when one writes a robust general-purpose facility (library)
>>> that will be used in an environment supporting cancellation, that
>>> library ought to be written to support cancellation (whether or not
>>> it actually uses cancellation on its own behalf). Such libraries
>>> are not generally tasks taken on by "casual users"; and even so
>>> while hardly ideal it's perfectly adequate to simply say "this
>>> facility isn't cancel-safe; tough luck".
>>>
>>> "Industrial strength" libraries in the environment, for example the
>>> "language runtime" itself, whether libc or STL, ought to be
>>> cancel-safe certainly. Even at that, however, because the task can
>>> be monumental, POSIX provided "cheats" -- the list of "optional"
>>> cancellation points allow a libc developer to omit all but the most
>>> critical. A C++ standard for STL *could* provide similar "cheats"
>>> to avoid requiring full implementation of cancel-safety. And again,
>>> if the user of the library (whether the main application or another
>>> library) doesn't choose to use cancellation the point is moot.
>>>     
>>
>> Picking this thread up from long ago, lete me say that I'm sort-of in
>> agreement with the above.  I say "sort of" because Dave B's statement
>> fails to address the following point (hereafter known as "the
>> statement"), and I can't tell what side of it he'd come down on:
>>
>>    Any code that is already exception-safe could be automatically
>>    cancel-safe depending on our definition of "cancel-safe" and the
>>    semantics we assign to cancellation exceptions.
>>
>> In the definition of "cancel-safe" that allows the statement to be
>> true, cancellation is a request, and doesn't absolutely force
>> _anything_ to happen.  IIUC, that is the status quo anyway (nobody is
>> even forced to invoke a cancellation point).
>>
>> The cancellation exception semantics that allow the statement to be
>> true are that they act like any other exception, and are not
>> automatically rethrown at the end of catch blocks.  This is the
>> question primarily in dispute, IIUC.
>>   
> This has been THE most contentious issue in every C++/threads discussion 
> I've encountered since the beginning of (pthread) time.
>
> My preference has always been that cancellation is an exception. Period. 
> In our initial CMA architecture, and in our exception mapping of 
> cancellation/thread-exit onto C language exceptions in Tru64 UNIX and 
> OpenVMS, it's possible and reasonable to finalize propagation of a 
> cancel/exit exception. That was critical for DCE, for example, so that 
> it could trap cancellation of an RPC server thread, bring the thread 
> back into the server's work pool, and propagate the exception across the 
> wire to the client.

That sounds highly analogous to my case with Python.

> To finalize a cancel/exit under almost any normal circumstance is
> simply an application error. 

The key word being "almost."  In some situations, like those we've
both cited, it's absolutely necessary, to even get cancellation to
work.

> There are many worse application errors, like infinite loops, that
> we can't legislate around anyway.  Worrying too much that someone
> might finalize the exception unintentionally just seemed like wasted
> effort. However it's also important to keep in mind that my
> preferences were formed with POSIX cancellation and C language (or
> cross-language OS) exceptions. C++ adds a lot of exception semantics
> and patterns on top of that.
>
> There have been plenty of people who argue that cancel "can't" be 
> caught; and some of these arguments trace back to the ubiquity of 
> catch(...), especially in constructors; 

A ctor that does catch(...) without rethrow is almost always badly
designed at best.  There was unfortunate advice going around for many
years that you shouldn't throw from ctors, but that's exactly wrong:
ctors that throw allow the establishment of strong invariants, and
programming without them is much harder.

On the other hand, stopping exceptions in dtors is absolutely the
right thing to do.

> and they have some legitimate concerns about common C++ language
> patterns that might pretty much prevent a cancel from ever doing
> what a cancel should do.

Really, legitimate concerns?  I can't think of any recommended
patterns that would act that way.

> The catch lies in whether (and how far) you'll trust application
> developers to do the re-throw properly. If we don't clean up all
> frames and eventually re-throw the cancel/exit to the runtime's base
> frame to terminate the thread, then we don't have cancellation.

I'm of the school that says it's futile and even dangerous to try to
operate correctly in an environment where you have to assume other
code is incorrect.  My library will probably be equally broken if the
user decides to throw out my bad_alloc exception without a proper
response.

> On the other hand, if we prevent a catch or force a re-throw, we
> lose a lot of C++ (particularly in constructors).

I don't think that should be your concern.  The correct and
well-written C++ we lose is generally sitting at module and language
boundaries.  And then there are dtors.

> Part of the reason that you "can't tell what side of it [I'd] come
> down on" is that I've long recognized this as an essentially
> religious rather than technical argument.  You'll come down on the
> side of the semantics toward which you feel the strongest emotional
> attachment.  

You don't find the idea that exception-safe code implies cancel-safe
code technically compelling?  I don't think that's an emotional issue.

> While I'm happy to express my experience and even preferences, I
> also recognize that "the other side" has some equally strong
> arguments and expectations, and they (well, most of them!)  are not
> "wrong".

I don't think either side is "wrong," either.  

> Someone needs to propose and champion "the great exception
> compromise"; but if that's to be me I don't yet have the faintest
> germ of a notion what it might be. So I sure hope it's going to be
> someone else. ;-)

If "finalized cancellation exceptions result in a new throw at the
next cancellation point" isn't enough of a compromise, it isn't going
to be me either, because I'm out of new ideas.

Okay, how about this one: we count the number of times the
cancellation is discarded.  The cancelling thread can specify the
number of discards to tolerate, where the default is infinite.  After
that, at the next cancellation point all pthread cancellation handlers
(but not dtors or catch blocks) are run and the thread is terminated.
Heck, at that point I don't care what happens; you're gambling anyway.
Run all the dtors and catch blocks for all I care.

A simpler approach might be to have two kinds of exception: "forced"
and finalizable.  At least then we can say that exception-safe code
implies finalizable cancellation safety.  Then "forced" synchronous
cancellation can do whatever people desire.  I personally think it
will become a useless appendage sort of like C++ exception
specifications, but at least evolution will take care of it.  And if
I'm wrong, evolution will wilt my finalizable cancellations.

I guess I'm not totally out of ideas ;-)

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com