[c++-pthreads] concrete library-code example
Dave Butenhof
David.Butenhof at hp.com
Mon Jan 5 16:57:32 UTC 2004
Nathan Myers wrote:
>On Wed, Dec 24, 2003 at 08:09:57AM -0500, Jason Merrill wrote:
>
>
>>On Tue, 23 Dec 2003 11:03:14 -0500, Ted Baker <baker at cs.fsu.edu> wrote:
>>
>>
>>>How do you propose to modify read() to throw an exception and
>>>still have backwards compatability with applications that expect
>>>read() to always return (more specifically, to return -1 if it
>>>fails)?
>>>
>>>
>>read() already doesn't return if it's acting on a cancellation request.
>>Throwing an exception is just a different way of not returning.
>>
>>
First, let me say, "ouch, my brain hurts". I've been on vacation for 2
weeks, and this mailing list had just started when I left, and the
traffic during that time is a bit overwhelming! I haven't finished yet,
and I don't expect to today. Nevertheless, I'm going to offer some
comments while I'm "inspired". I'll also comment (with some degree of
surprise and perhaps even consternation) that so far I've seen nothing
to suggest that an eventual more detailed response will differ in any
great detail from the comments made by Alexander Terekhov. But then, as
I said, I haven't finished catching up yet. ;-)
>Enlarging on this question...
>
>Here is a more-or-less concrete example, for discussion purposes.
>It's meant as a generic example of code written according to the
>existing contract offered by C libraries.
>
>
Correction: "... offered by C libraries that support POSIX 1003.1b-1993
or earlier."
> int affect_world(struct state* s)
> {
> int result;
> violate_invariants_or_claim_resources(s);
> result = c_function_or_system_call(s->member);
> if (result < 0) {
> clean_up(s, result);
> return result;
> }
> act_on_result(s, result);
> restore_invariants_and_release_resources(s);
> return 0;
> }
>
>This pattern is extremely common in both C and C++ libraries. If
>read() were to throw (or to "just ... not return"), the program state
>would be corrupted. A redefinition of c_function_or_system_call
>semantics that breaks this code breaks many thousands of existing
>thread-safe C and C++ libraries.
>
>
If this code exists in a pure ANSI C/POSIX application using threads,
and if the thread running this code can be cancelled, then the
implementation of this function is broken because IT (not the
implementation, nor the cancellation) corrupts program state.
While I'm not at all trying to argue that the issue is at all as simple
as this, that's the facts all the same.
Depending on propagation of error statuses is a really bad way to
implement cancellation. At least, given the primitive and limited
concept of ANSI/POSIX error codes. Too much code ignores statuses in the
first place, which is bad enough. But, worse, there are many legitimate
reasons for library code to CONVERT return status values; e.g., I called
read() and it returned some error but MY function only implicitly
involves a read() and it simply wouldn't be useful or meaningful to
return that error to my caller. Instead, I want to indicate that my
function (say, synchronizing a database) failed, and so any (or at least
most) failures of my "support calls" will result in my returning 'unable
to synchronize database' (which often isn't an ANSI/POSIX error number
in the first place, but even if it is, it's unlikely to be the value
returned by read). The ECANCELLED some have proposed would be lost, and
that's unacceptable. This is why we settled on exceptions to represent
cancellation. And because POSIX and ANSI C don't have exceptions, we
devised the simple "cleanup handler" mechanism that allowed a clean and
transparent implementation on top of exceptions, or a "hack"
implementation private to the thread library where exceptions weren't
available.
>(The cancellation model described in
> http://www.codesourcery.com/archives/c++-pthreads/msg00021.html
>is designed to preserve libraries that contain code that follows
>this pattern.)
>
>Jason, do you not consider those libraries worth preserving?
>
>
If you're talking about a currently non-threaded library to which you'd
like to transparently add thread support; well, I doubt that's possible,
and this particular proposal isn't going to help. When they're
redesigned and recoded to be thread-safe, they can also be made
cancel-safe. If you're talking about adding cancel support transparently
to an existing C++ library, I doubt this is sufficient unless there's
some standard requirement that all C++ libraries must pass through the
system failure code to the caller. (There isn't, can't be, and shouldn't
be.) And it also presupposes that the C++ library isn't exception-safe;
because if it is, then delivering cancellation as an exception would
seem "obviously" to be the most compatible and complete solution.
And I'm deliberately discounting the mention I've seen several times in
this list of "thread-safe" libraries that aren't "cancel-safe". Such
libraries are simply broken, from basic design. Cancellation is a basic
and important part of the POSIX thread model, and if you're not safe
you're not safe. The only viable exclusion (there, I avoided using the
word "exception", though it took me a few moments of thought) is if you
can be guaranteed to be running only in threads that can never be
cancelled... and in that case the whole issue is irrelevant!
--
/--------------------[ David.Butenhof at hp.com ]--------------------\
| Hewlett-Packard Company Tru64 UNIX & VMS Thread Architect |
| My book: http://www.awl.com/cseng/titles/0-201-63392-2/ |
\----[ http://homepage.mac.com/dbutenhof/Threads/Threads.html ]---/
More information about the c++-pthreads
mailing list