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

Dave Butenhof david.butenhof at hp.com
Wed Mar 8 02:22:32 UTC 2006


David Abrahams wrote:
> Dave Butenhof <david.butenhof at hp.com> writes:
>   
I'm cutting off a lot of the top part. It's getting long, the discussion 
isn't really going anywhere relevant to the root topic, and we're 
probably better off just dropping it. That, at any rate, is my 
preference. ;-)
>> Ah, but cancellation is basically asynchronous with respect to the 
>> receiving thread. 
>>     
> Not the kind of cancellation that uses cancellation points.
> "Asynchronous exception" means an exception that emanates from code
> that is not allowed to throw unless undefined behavior is invoked.
> Everything else is a synchronous exception.  If you call some of that
> latter stuff "asynchronous," (a)synchronicity of exceptions becomes a
> useless distinction.
>   
The entire point of threads is that their operation is asynchronous. 
Everything about the design of a threaded application, a runtime and OS 
that support threads, a LANGUAGE that supports threads, has to be to 
deal with asynchrony -- with parallel call stacks running 
simultaneously. Anything that happens in or because of a thread is 
asynchronous with respect to other threads.

Deferred cancellation is a "conversion interface" to allow the 
asynchronous external event to manifest synchronously in the target 
thread, for ease and consistency of cleanup. But that doesn't make the 
event synchronous, and I think that the distinction is important.

Cancellation is asynchronous up to the point where the exception is 
thrown, synchronously, by the target thread to unwind and terminate. A 
blocking read operation isn't cancelled synchronously at the beginning 
or end of the operation, or even the beginning or end of the blocking 
part of the I/O -- it can be interrupted asynchronously somewhere in the 
middle. In my implementation, I initiated the unwind (the "throw") from 
the interrupt handler, if cancellation is enabled, rather than deferring 
it until the unblocked operation wakes up... though that would certainly 
be another alternative.
>> Even though we deliver the exception only at defined synchronous
>> points, the cancellation request can arrive at any instant.  
>>     
> But exactly when it arrives is irrelevant with respect to the
> receiving thread.
>   
I suppose you can reasonably argue that. I think that understanding the 
model is important when you making coding decisions.
>> This is mostly relevant when you talk about blocking behavior --
>> that a blocking operation can be interrupted anywhere in the middle
>> IS asynchronous.
>>     
> Huh?  It sounds like you're interested in some detail that I don't yet
> have context for.
>   
Perhaps I'm worried about thought models and implementation while you're 
concerned with appearance. Both views are certainly valid within certain 
domains.
>> "Deferred" cancelability converts that asynchronous interrupt into a 
>> synchronous exception, though the definition of the blocking operation 
>> as a cancellation point. So the cancelled thread doesn't necessarily see 
>> the exception as "asynchronous" (it called a function, and got back an 
>> exception); but that doesn't change the fact that it really was 
>> asynchronous all the same.
>>     
> Cancellation can be as asynchronous as you like from that definition.
> The resulting exception is still synchronous.
>   
Right. Cancellation is asynchronous. The exception that notifies the 
thread of cancellation is synchronous. There we go. That's the 
conversion interface.
>> But I don't mean it in anything like the sense of "asynchronous 
>> cancelability mode", where the exception can be raised (cancel 
>> delivered) at any arbitrary point. 
>>     
> Good.  Let's pick different terms that don't lead to this confusion,
> please.
>   
But C++ people should be good at overloading. ;-)

"Asynchronous cancelability type" is (at least potentially) an 
asynchronous EXCEPTION in response to an asynchronous event, while 
"deferred cancelability type" is a synchronous (deferred) exception in 
response to the same asynchronous event. Does that help?

Cancelability type affects only the DELIVERY of notification within the 
target thread, not either the "launching" or "delivery" mechanisms of 
cancellation.
>> However, when cancellation is enabled, any blocking call (or any
>> method/operator that makes or might make a blocking call, like
>> "cout<<", might raise an exception. Not all code will be prepared to
>> handle that, and much shouldn't be; it's important to be able to
>> disable cancelability dynamically over critical scopes. It's not
>> like most exceptions where the conditions for an exception are
>> generally static; it could happen at any time for reasons the
>> current thread cannot possibly anticipate.
>>     
> That's exactly like most exceptions (c.f. out-of-memory).  Usually
> conditions whose reasons can be anticipated can be effectively tested
> and become preconditions or simply should be reported by other means.
>   
Sometimes. Exceptions are great for "out of band" notifications that may 
not be intended for the direct caller; they can be picked up with full 
state, and without additional mechanism, by anyone along the call path 
who cares.
>> and I'm much less ignorant than I was 2 years ago when I started
>> working with C++ and STL on a regular basis. Still, I am not steeped
>> in the history and tradition of C++ as I am in threads, and probably
>> never will be. More than that, while I have an authoritative voice
>> on the POSIX working group and in the community, I'm not involved
>> with the C++ committee and have no time or management support to get
>> involved; and I won't put myself in the position of being an outside
>> expert in some other area pretending to tell the C++ committee what
>> it must (or even should) do.
>>     
> I don't think you should.  There are other areas where you could make
> a big difference, though, like the ISO committee for C++/POSIX binding
> Mr. Drepper is now running.
>   
"ISO committee" is rather a strong description; it's a simple mailing 
list that's hoping to gain some preliminary consensus towards 
constructing a formal proposal to request permission to develop a 
charter and start a working group with the intent of building a proposal 
for a binding. But, yeah, OK, fine. ;-)

In any case, I am following it, and contributing to the (sporadic) 
discussions. In fact, when I got your re-opening of this mailing list I 
initially thought you were writing to that one; though this discussion 
is rather more detailed and relevant than what we've seen so far on the 
other.

I will get as involved as I can given my time constraints, but we'll see 
what that amounts to as the mailing list discussions progress. I assure 
you that if I hold back it's not for lack of interest or motivation. ;-)
>>> No, I wasn't suggesting anything that couldn't be caught.  I was just
>>> suggesting an exception that couldn't be stopped.  It could throw
>>> itself in its dtor (not that I'm advocating it, but it might satisfy
>>> the "other side"), for example.
>>>       
>> The POSIX model where cancel propagates inexorably to thread termination 
>> is an inherently flawed compromise; but simply the best we could do 
>> within the context of ISO C and POSIX APIs. OUR implementation always 
>> allowed finalization, via C++ catch(...), our ISO C "CATCH_ALL" 
>> extensions, or whatever other language syntax might fit.
>>
>> I really wouldn't want to propagate this restriction to C++.
>>     
> Be clear, I'm not talking about a restriction.  If you ask it to throw
> something normal, it's finalizable in the normal way.  This is a way
> for the _cancelling_ thread to say, "I know what I'm doing; the author
> of the thread I'm cancelling doesn't.  Force it to be killed at the
> next cancellation point."
>   
The whole concept of cancellation is exactly that the TARGET thread, not 
the cancelling thread, knows what it's doing and should control the 
cleanup and termination entirely. Without explicit synchronization, the 
cancelling thread can't know what it's doing and whether a forced abort 
is appropriate or safe. And if it has enough synchronization to know 
that, there are far better ways to gain a cooperative termination than 
cancellation.
>> One advantage, though, of the single cancel exception, is that it's 
>> universal. When you asynchronously issue a cancel request for a thread, 
>> you can't really know what code is executing: your's, STL, some other 
>> shared library, etc. Cancel means the same to all of them, and either is 
>> supported with commonly agreed semantics or will be ignored (by 
>> disabling cancellation in critical scopes). Once you start firing off 
>> your own arbitrary exceptions, though, anything might happen because 
>> half the time the exceptions won't belong anywhere in the call tree 
>> that's active at the time they arrive.
>>     
> That's not the way most exception-safe code works.  It goes to the
> reason that exception-specifications are a failure: the particular
> type of exception that propagates out of a throwing function makes
> almost no difference to anyone.  The type only becomes important where
> errors are reported, or where exceptions are translated -- either to
> other exception types or, for example, to error return codes that can
> propagate through other languages.  So the danger of injecting an
> arbitrary exception type into existing code (especially libraries,
> which are very often exception-neutral) is very very low.
>   
That's an intriguing statement. I'll need to think about that some.

I've certainly always thought that exception specifications were little 
more than a trap into which people could mire themselves as deeply as 
they like. So maybe that means I agree. I'm not sure. ;-)

I guess I'd have to agree that the danger of injecting another exception 
type is low. And mostly due to the fact that C++ has no "root exception 
type" onto which could be grafted some minimal universal state (an 
architected status code space, like VMS condition codes, a descriptive 
string, etc.) so that nobody would need an anonymous and semantic-free 
catch(...) just to be sure nothing slipped past.
>> Which brings us back to the "academic" resolution: if an exception
>> means distinct things in different call trees, those call trees
>> should be distinct threads and only one universal exception is
>> necessary. ;-)
>>     
> I think you might be missing the point.  I am proposing the generalized 
>
>   thread_throw( thread_id, exception_object )
>
> function so that those who wish to hang themselves with homegrown
> unstoppable exception types can do so without forcing the standard to
> sanction the use of unstoppable exceptions by providing any kind of
> "forced cancellation."  If "the other side" has A WAY to force
> cancellation, maybe they won't insist it has to be THE WAY.  I know,
> wishful thinking :)
>   
I'm not sure how sanctioning generalized unstoppable exceptions is going 
to mollify anyone opposed to an unstoppable variety of a specific 
exception. At best, cancel becomes a subset of cross-thread throw with 
specialized additional deferral semantics. And if you're generalizing 
the unstoppable exception, I don't quite see how it makes sense not to 
generalize the deferral, and now cancel really is just a specific 
predefined exception that can be thrown like any other exception. That's 
not necessarily bad; I just don't see how it's a compromise. (A 
compromise needs to make BOTH sides equally unhappy, not just one side!)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: david.butenhof.vcf
Type: text/x-vcard
Size: 476 bytes
Desc: not available
URL: <http://sourcerytools.com/pipermail/c++-pthreads/attachments/20060307/23fd6799/attachment.vcf>


More information about the c++-pthreads mailing list