[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