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



David Abrahams wrote:
Dave Butenhof <david.butenhof@xxxxxx> 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!)
begin:vcard
fn:Dave Butenhof
n:Butenhof;Dave
org:Hewlett-Packard Company;Manageability Systems Lab
adr;dom:110 Spit Brook Rd;;ZKO2-3/Q18;Nashua;NH;03062
email;internet:david.butenhof@xxxxxx
title:HP Utility Pricing software agent Technical Lead
tel;work:603.884.7460
note;quoted-printable:POSIX thread standards consultant=0D=0A=
	Author of "Programming With POSIX Threads" (Addison-Wesley)=0D=0A=
	Father to Amy (12) and Alyssa (8)
x-mozilla-html:TRUE
version:2.1
end:vcard