Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

are C++ destructor called when thread is canceled?

560 views
Skip to first unread message

Jianhua Sun

unread,
Apr 24, 1997, 3:00:00 AM4/24/97
to

what happens to a C++ object when a thread is canceled? is its
destructor called?

Jay

Renato Ghica

unread,
Apr 25, 1997, 3:00:00 AM4/25/97
to

The destructor is not called simply because pthread_cancel()
is called. pthread_cancel() might not even work when you want it to!


pthread_cleanup_push/pop macros can be used to call a routine
that should be used wnen a thread is terminated.

So, yes, the destructor won't get called If you cancel a thread,
anymore more that a DCE server will unregister itself if you
do a "kill -9" on it, or a kill without setting up an signal
handler.


--
X-no-Archive: Yes

----------------------------------------------------------------
Any comments or statements made are not necessarily those of
J.P. Morgan & Co. Incorporated, its subsidiaries or affiliates.
----------------------------------------------------------------

Dave Butenhof

unread,
Apr 25, 1997, 3:00:00 AM4/25/97
to

Jianhua Sun wrote:
>
> what happens to a C++ object when a thread is canceled? is its
> destructor called?

Destructors SHOULD be called, logically, on cancellation.

Given a "well integrated" thread implementation and C++ runtime, they
WILL be called.

However, POSIX does not address C++, and does not require that they be
called. C++ does not address threads, and does not require that they be
called. Therefore, this is strictly a "quality of implementation" issue.
If you've got a C++ compiler and threads implementation that don't work
together, you should immediately complain to the vendor(s) and get them
to solve the problem. But be aware that you have nothing but logic and
reason behind your arguments.

/---[ Dave Butenhof ]-----------------------[ bute...@zko.dec.com ]---\
| Digital Equipment Corporation 110 Spit Brook Rd ZKO2-3/Q18 |
| 603.881.2218, FAX 603.881.0120 Nashua NH 03062-2698 |
\-----------------[ Better Living Through Concurrency ]----------------/

Ben R. Self

unread,
Apr 26, 1997, 3:00:00 AM4/26/97
to

Jianhua Sun wrote:
>
> what happens to a C++ object when a thread is canceled? is its
> destructor called?
>

> Jay

Dave Butenhof wrote:
>
> Destructors SHOULD be called, logically, on cancellation.
>
> Given a "well integrated" thread implementation and C++ runtime, they
> WILL be called.

> ...

Renato Ghica wrote:
>
> The destructor is not called simply because pthread_cancel()
> is called. pthread_cancel() might not even work when you want it to!

> ...

For the record I agree with Dave Butenhof. Unfortunately the reality is
somewhat different.

I routinely work with about a dozen different threaded platforms. In
almost all cases, including NT/95, upon cancelation or explicitly
exiting a thread the C++ call stack does not get cleaned up.
Destructors are not called, resources are not freed. It reminds me all
too much of early implementations of exception handling. The only
platform I have had consistanly good results with, in this regard, is
Solaris. While I am thinking about it, I recall newer versions of
Digital's implementation also working correctly.

But as for DCE threads, IRIX, and most of the rest, you are out of luck.

--ben

-----------------------
Ben R. Self
bs...@opentext.com
www.opentext.com

Open Text, Inc -- Home of Livelink Intranet

Ben Elliston

unread,
Apr 28, 1997, 3:00:00 AM4/28/97
to

> what happens to a C++ object when a thread is canceled? is its
> destructor called?

Absolutely not. That's half the problem (or more than half the problem!)

One way around this is to implement cooperative thread cancellation where
you either:

a) flag a thread to terminate, and the thread
checks this flag at convenient times.

b) set up a per-thread signal handler which
catches SIGUSR1 (say) and then executes
a signal handler to clean up.

Both ways seem to work OK, the second being a bit dirtier, but more
effective.

Cheers,
Ben

--
Ben Elliston E-mail: ben.el...@compucat.com.au
Compucat Research Pty Limited WWW: <http://www.compucat.com.au>
Fyshwick ACT Australia


Eric Kenslow

unread,
Apr 28, 1997, 3:00:00 AM4/28/97
to

My method for dealing with this problem is a combination of
the approaches you mention. Here's the basic algorithm:

1) Thread A starts thread B.
2) Thread B runs, periodically checking for the 'die' flag (under
Windows NT, this is an event that will be set at death time).
3) Thread A decides it's time for B to go away. It calls A->Kill(),
then A->Join() (to wait for B to die gracefully) with a timeout value.
If B goes away gracefully, skip to step 5.
4) Thread A assumes that B has hung and forcefully terminates it
(under NT, calls TerminateThread()).
5) Thread A deletes thread B's object, thus (in a perfect world)
reclaiming all of thread B's resources.

Although this technique requires extra bookkeeping
(potentially a LOT of extra bookkeeping) on A's part, IMHO it turns
threading objects' disadvantage into assets- normally, the problem
with this kind of cleanup is that your thread object's members may
execute in the context of multiple threads. Here, though, we use that
to our advantage by treating the thread that the object encapsulates
as a slave, with its lifetime ultimately controlled by the master
thread.

Renato Ghica

unread,
Apr 28, 1997, 3:00:00 AM4/28/97
to

Ben R. Self wrote:


>
> Jianhua Sun wrote:
> >
> > what happens to a C++ object when a thread is canceled? is its
> > destructor called?
> >

> > Jay
>
> Dave Butenhof wrote:
> >
> > Destructors SHOULD be called, logically, on cancellation.
> >
> > Given a "well integrated" thread implementation and C++ runtime, they
> > WILL be called.
> > ...
>
> Renato Ghica wrote:
> >
> > The destructor is not called simply because pthread_cancel()
> > is called. pthread_cancel() might not even work when you want it to!
> > ...
>
> For the record I agree with Dave Butenhof. Unfortunately the reality is
> somewhat different.

Of course the destructor *should* get called - But there is just no
bridge between
posix threads and C++ at this time. Also this would imply that a method
to "really"
terminate a thread would also have to be supplied. Maybe you don't want
the thread
to do more CPU cycles after a pthread_cancel, maybe you want it to just
STOP.

>
> I routinely work with about a dozen different threaded platforms. In
> almost all cases, including NT/95, upon cancelation or explicitly
> exiting a thread the C++ call stack does not get cleaned up.
> Destructors are not called, resources are not freed. It reminds me all
> too much of early implementations of exception handling. The only
> platform I have had consistanly good results with, in this regard, is
> Solaris. While I am thinking about it, I recall newer versions of
> Digital's implementation also working correctly.
>

But even on Solaris, the man page for pthread_cancel states that
thread destruction is not guaranteed as a result of the call. And it
also
happens that destructors don't get called there either (DCE 1.1/Solaris
2.5.1) even
when the thread is cancelled.


So the only platforms where "the destructors will get called" might be
some "newer versions" of Digital's DCE.


If anyone can point to a DCE implementation where destructors do get
called,
I'd like to know about it. Or if there is a solaris platform where that
happens,
that would be good also.

thx

-rg

Ben Self

unread,
Apr 28, 1997, 3:00:00 AM4/28/97
to

Renato Ghica wrote:
>
> But even on Solaris, the man page for pthread_cancel states that
> thread destruction is not guaranteed as a result of the call. And it
> also
> happens that destructors don't get called there either (DCE 1.1/Solaris
> 2.5.1) even
> when the thread is cancelled.
>
After reading over my original post it strikes me that I was giving the
impression that I routinely bet the farm on destructors being called on
Solaris as the result of pthread_cancel() or pthread_exit() and have had
no problems doing so.

This IS NOT the case. You cannot portably do so. And even Solaris
makes no guarantees that it will work. There are still the big issues
of Syncronous vs Asynchronous cancelation as well as a miriad of other
potential gotchas. All I really wanted to state is that I have seen
destructors called properly for Solaris in this situation and to reward
them for making the attempt.

The following ridiculously simple code works properly for me under
Sloaris 2.5.1 compiled with Sun WorkShop C++ 4.2:

#include <pthread.h>
#include <iostream.h>
#include <unistd.h>

class foo
{
public:

foo() { cout << "ctor" << endl; }
~foo() { cout << "dtor" << endl; }
};

void* thread( void* )
{
foo f;

while ( 1 )
{
sleep( 5 );
}

return 0;
}


int main()
{
pthread_t t;

pthread_create( &t, 0, thread, 0 );

sleep( 1 );
pthread_cancel( t );

pthread_join( t, 0 );
}


hope this clears up some things.

Hr.McCann

unread,
Apr 29, 1997, 3:00:00 AM4/29/97
to

Ben Self (bs...@opentext.com) wrote:

: Renato Ghica wrote:
: >
: > But even on Solaris, the man page for pthread_cancel states that
: > thread destruction is not guaranteed as a result of the call. And it
: > also
: > happens that destructors don't get called there either (DCE 1.1/Solaris
: > 2.5.1) even
: > when the thread is cancelled.
: >
: After reading over my original post it strikes me that I was giving the
: impression that I routinely bet the farm on destructors being called on
: Solaris as the result of pthread_cancel() or pthread_exit() and have had
: no problems doing so.

This is the behaviour I've seen as well. The "native" POSIX.1c threads on
Solaris 2.5.1 *do* call destructors of C++ stack objects upon cancellation,
the Transarc DCE 1.1 thread package *doesn't*.

Hope this clears up the difference of opinion here,

David.

===========================================================================
David McCann B.Sc.(Hons) | MAIL: David . McCann @ siemens . at
PSE TMN 23 | (Remove spaces for address to work)
Siemens AG Austria |
Gudrunstrasse 11 | VOICE: +43 1 1707-45606
A-1101 Wien | FAX: +43 1 1707-55712
===========================================================================

James Mansion

unread,
Apr 30, 1997, 3:00:00 AM4/30/97
to

I think you will find that this is not an OS issue per se, but an
artifact of the way that the C++ compiler handles exceptions.

If the cancel results in a signal and that is captured and converted
into an exception then you have some hope that it will work.

Indeed, Microsoft changed their default implementation with VC5, for
example, so that you can choose whether a trapable event causes what
they call an 'asynchronous exception' or whether the exception mechanism
works with C++ thrown exceptions only.

One can see an argument in favour of either approach - certainly wrting
any code that requires this behaviour is very dangerous in the absence
of any standardisation, whether or not 'good' implementations provide
it.

Question:

void foo() throw ()
{
::sleep(1) ;
}

What happens if the pthread_cancel hits me in the sleep here?
unexpected? or is this case special and the caller stack will
unwind 'as if' foo had thrown an exception?

James

--
Westongold Ltd C++/Java
Multithread development and libraries
+44 1920 444284 in...@westongold.com

Dave Butenhof

unread,
Apr 30, 1997, 3:00:00 AM4/30/97
to

Renato Ghica wrote:
>
> Of course the destructor *should* get called - But there is just no
> bridge between
> posix threads and C++ at this time. Also this would imply that a method
> to "really"
> terminate a thread would also have to be supplied. Maybe you don't want
> the thread
> to do more CPU cycles after a pthread_cancel, maybe you want it to just
> STOP.

That (the last part) doesn't follow, because there's no concept of
"stopping a thread dead" in POSIX. And, if there were, it would have
nothing to do with cancellation. The whole point of cancellation is that
it provides a controlled way to protect shared state while getting a
thread "out of the way as soon as practical". Cancellation is, really,
nothing more than a special cross-thread exception.

During the early days of the original CMA architecture (from which the
POSIX cancellation model descends) we had considered supporting
generalized cross-thread exceptions (CMA was based on exceptions, which
didn't survive the transition to POSIX because POSIX doesn't -- and
can't -- provide any such thing). We decided that the generalization
wasn't necessary or useful because threads provide a sufficiently
inexpensive level of modularity that it's reasonable to restrict what a
thread does so that a single exception (cancel) is enough. Whether this
decision was right no longer matters, since POSIX scooped it up.

A "C++ binding to POSIX" (as 1003.1 is a C binding) might reasonably
include various cross-thread exception and termination models, as Java
has, if there ever is such a beast.

> > I routinely work with about a dozen different threaded platforms. In
> > almost all cases, including NT/95, upon cancelation or explicitly
> > exiting a thread the C++ call stack does not get cleaned up.
> > Destructors are not called, resources are not freed. It reminds me all
> > too much of early implementations of exception handling. The only
> > platform I have had consistanly good results with, in this regard, is
> > Solaris. While I am thinking about it, I recall newer versions of
> > Digital's implementation also working correctly.

Win32 doesn't support "graceful" cross-thread shutdown, only random
messy termination. Not that it can't be built, but it's not standard.
That makes integration of cancellation with the exception model
"challenging". (It's been done, however.)

> But even on Solaris, the man page for pthread_cancel states that
> thread destruction is not guaranteed as a result of the call. And it
> also
> happens that destructors don't get called there either (DCE 1.1/Solaris
> 2.5.1) even
> when the thread is cancelled.

Don't get confused between the Solaris implementation of POSIX threads
and the Transarc DCE threads. There's very little connection. They're
not even done by the same company. They implement completely different
interfaces. DCE threads includes a hacky portable exception macro
package that's based on setjmp/longjmp, and it may well be that the
Solaris implementation uses our original macro package, whereas the
Solaris C++ almost certainly uses something completely different.

> So the only platforms where "the destructors will get called" might be
> some "newer versions" of Digital's DCE.

Whether destructors get called is more a matter of how the C++ runtime
works than DCE. As I said, the DCE exception macro package (on which
cancel was based) is pretty kludgy and self-contained, making it
difficult to integrate with a real language mechanism.

> If anyone can point to a DCE implementation where destructors do get
> called,
> I'd like to know about it. Or if there is a solaris platform where that
> happens, that would be good also.

Digital UNIX has an architecturally specified exception model, which is
used by our POSIX threads, C++, Ada, and other languages that support
exceptions. The C compiler has extensions that allow "native" exception
handling (based on the Microsoft C extensions). (It's ugly, but it
works.) For the most part, each language deals only with its own
exceptions -- they all have different ideas of what information is
captured, and how exceptions are represented, that are hard to unify.
However, they all have some type of "finalization" support (Ada and C
"finally" clauses, C++ destructors, the DCE thread FINALLY macro) that
don't care about the representation of an exception. All of these will
fire smoothly when any exception breezes through the stack past their
call frame. Because cancellation is an exception, it works just fine.

Bruce Bigby

unread,
May 2, 1997, 3:00:00 AM5/2/97
to James Mansion

James Mansion wrote:
>
> I think you will find that this is not an OS issue per se, but an
> artifact of the way that the C++ compiler handles exceptions.
>
> If the cancel results in a signal and that is captured and converted
> into an exception then you have some hope that it will work.

Although I haven't had the priveledge of practicing my knowlege of C++,
I am surprised that C++ does not handle asynchronous OS/Hardware
exceptions. Why didn't the implementors account for this? Eiffel, I
believe, has supported HW exceptions since its inception.

However, I wrote a package in C which supports exceptions and that can
even tame HW exceptions by preventing the OS from delivering them until
a program can cleanly handle them. In the try block of an exception
handler, the program allows delivery of OS/HW exceptions/signals. If
the program receives an OS/HW exception, while in the try block, the
exception handler transfers control to the catch block. Once in the
catch block, the exception handler blocks all signals from delivery,
allowing the program to handle the current exception and cleanup without
interruption. If the routine does not handle the exception, then the
exception handler returns control to the catch block of the most
recently created exception handler. If the program handles an exception
cleanly and exits the exception handler, the handler allows the OS to
deliver any outstanding signals. If there is an outstanding HW/OS
exception/signal, then the exception handler transfers control to the
most newly created exception block. If no exception block exist, then
the exception handler aborts the program.

I'm in the process of making this library pthread-safe. I already know
what to do, but I have to figure out this whole mess with regard to
signals and threads. It's gonna be fun.

Keep in mind that blocking and unblocking HW/OS signals can be expensive
because these actions involve kernel calls. Alternatively, you could
optionally handle HW/OS exceptions. This would allow you to tell the
exception facility that it does not have to block and unblock OS/HW
exceptions from delivery. In this case, you might also have to decide
whether the exception facility should ignore HW/OS exceptions entirely
or allow the program to receive them and abort. Of course, their are
some HW/OS exceptions/signals that a program cannot, or should not,
ignore.

I suppose that one can make the kernel calls to block and unblock
signals more efficient, but I believe that this is kernel-dependent.
For example, I tested my exception facility for the case where it
handled OS/HW exceptions and the case where it did not. For the case
where it did handle OS/HW exceptions, on my 386 Linux computer, a
program, that I wrote, was able to execute 3700 null exception blocks
per second when handling HW/OS exceptions/signals. When not handling
HW/OS exceptions, the program was able to excecute over 30,000 null
exception blocks per second. Basically, the program would setup the
exception handler and remove the handler, repeating this for a period of
one second. Consequently, the program was 8 times slower when
accounting for OS/HW exceptions/signals.

Now that I have a Pentium 133, the performance of the exception facility
when accounting for HW/OS exceptions/signals improved to 44,000
executions per second. I have not tested the case where it does not
handle OS signals. This should be much higher, but I suppose that this
really depends upon the kernel that I use, and whether the calls to
block and unblock signals have become a lot more efficient or have
stayed relatively the same. If this is true, I would expect that the
performance without handling OS/HW exceptions would be about 356,756
iterations / second, or 2.8 usec per execution. I suppose that one can
argue that, for some applications, the speed is worth the risk. The
time per execution, when handling OS/HW exceptions, would be 28
usec--not terrible, but still probably much slower than the time when
not handling OS/HW exceptions. Remember: My timing for the case, where
the program does not handle OS/HW exceptions, is an extrapolation.

Like I said, you can write your programs to block all OS signals, if you
want, or to handle them. It's up to you.

>
> Indeed, Microsoft changed their default implementation with VC5, for
> example, so that you can choose whether a trapable event causes what
> they call an 'asynchronous exception' or whether the exception mechanism
> works with C++ thrown exceptions only.

I'm not sure what this means. Give an example.

>
> One can see an argument in favour of either approach - certainly wrting
> any code that requires this behaviour is very dangerous in the absence
> of any standardisation, whether or not 'good' implementations provide
> it.
>
> Question:
>
> void foo() throw ()
> {
> ::sleep(1) ;
> }
>
> What happens if the pthread_cancel hits me in the sleep here?
> unexpected? or is this case special and the caller stack will
> unwind 'as if' foo had thrown an exception?
>

I don't know about W95 or WinNT, but, for UNIX, sleep would probably set
errno to EINTR (Interrupted System Call). You would have to check for
this and throw the appropriate exception. Unfortunately, you don't know
which HW/OS signal caused the EINTR. I suppose that this is why SunOS
does not guarantee that pthread_cancel will succeed. Furthermore, for
most C libs on various platforms, errno is a shared global variable, and
this is a problem for threaded programs. For threaded programs, your
standard threads/C library would have to make sure that it supports/sets
a different errno for each thread.

I suppose that you could change the way that you write your programs.
Only use pthread_cancel as a last resort. Use message passaging via
mail boxes to communicate with your threads. If you want to cancel a
thread, cancel it via a message, then it can cleanup and exit
gracefully.

Always be careful/suspect of code that blocks. If your threads never
blocks, except on receiving a message via a mailbox, you can always
communicate with it. When you have to use a blocking call, you are
going to have to figure a stategy to make it die. For example, if a
pthread_cancel does not succeed on a thread, such as in a sleep call,
then, at least, the OS will interrupt it. The thread can abort because
it cannot know the signal that interrupted it, or report the problem to
a error log and continue as if nothing happened. Subsequently, you can
send a cancel message via a mailbox to get the thread to cancel.
However, you have execute the proper steps in your code to guarantee
that your program will exit gracefully.

> James
>
> Hr.McCann wrote:
> >
> > Ben Self (bs...@opentext.com) wrote:
> > : Renato Ghica wrote:
> > : >

> > : > But even on Solaris, the man page for pthread_cancel states that


> > : > thread destruction is not guaranteed as a result of the call. And it
> > : > also
> > : > happens that destructors don't get called there either (DCE 1.1/Solaris
> > : > 2.5.1) even
> > : > when the thread is cancelled.

> > : >
> > : After reading over my original post it strikes me that I was giving the
> > : impression that I routinely bet the farm on destructors being called on
> > : Solaris as the result of pthread_cancel() or pthread_exit() and have had
> > : no problems doing so.
> >
> > This is the behaviour I've seen as well. The "native" POSIX.1c threads on
> > Solaris 2.5.1 *do* call destructors of C++ stack objects upon cancellation,
> > the Transarc DCE 1.1 thread package *doesn't*.
> >
> > Hope this clears up the difference of opinion here,
> >
> > David.
> >

-
Bruce W. Bigby

James Mansion

unread,
May 5, 1997, 3:00:00 AM5/5/97
to

Dave Butenhof wrote:
> call frame. Because cancellation is an exception, it works just fine.

So, you throw an exception back over:

void foo() throw () ;

Or you call unexpected()? Or what?

You don't have any right to propagate an exception through a call to foo
without breaking the C++ model, and you don't have a C++ program flow
facility other than exceptions to allow you to do the stack unwind in
this way.

I'm not sure I'm with you on whether pthread_cancel does otherwise that
'stop a thread dead' with the specific exception of the cancellation
handlers
as in:

>That (the last part) doesn't follow, because there's no concept of
>"stopping a thread dead" in POSIX. And, if there were, it would have
>nothing to do with cancellation. The whole point of cancellation is that

The text for pthread_cancel says 'When the cancellation is acted on, the
cancellation cleanup handlers for the thread are called. When the last
cancellation cleanup handler returns, the thread-specific data
destructor
functions shall be called for thread. When the last destructor function
returns, thread shall be terminated.'

This doesn't entirely square with performing any other actions, such as
unwinding stacks - the cleanup handlers and destructor functions in this
case are explicit pthread entities. If your C++ implementation chooses
to link stack contexts into this framework then that's clearly an
extension.

Its not C++.

James

Jeff Gomsi

unread,
May 6, 1997, 3:00:00 AM5/6/97
to ben.el...@compucat.com.au

Ben Elliston wrote:
>
> > what happens to a C++ object when a thread is canceled? is its
> > destructor called?
>
> Absolutely not. That's half the problem (or more than half the problem!)
>
> One way around this is to implement cooperative thread cancellation where
> you either:
>
> a) flag a thread to terminate, and the thread
> checks this flag at convenient times.
>
> b) set up a per-thread signal handler which
> catches SIGUSR1 (say) and then executes
> a signal handler to clean up.
>
> Both ways seem to work OK, the second being a bit dirtier, but more
> effective.
>
> Cheers,
> Ben
>
> --
> Ben Elliston E-mail: ben.el...@compucat.com.au
> Compucat Research Pty Limited WWW: <http://www.compucat.com.au>
> Fyshwick ACT Australia

I think you have to be very careful about the SIGUSR1 type approach.
We tried this on Solaris 2.5 and SPARCWorks 4.1 C++ with varying
success. We installed a SIGUSR1 handler which then threw a C++
exception to unwind the call stack and call the destructors. The
idea worked in simple test cases but produced some bad problems
in our more comp-lex production stuff, so we had to go back to
option (a).

You have this same problem if you exit a thread down in a nested
series of calls. No destructors get called when the stack unwinds.

It's really too bad the vendors don't address this problem.

Dave Butenhof

unread,
May 7, 1997, 3:00:00 AM5/7/97
to

James Mansion wrote:

>
> Dave Butenhof wrote:
> > call frame. Because cancellation is an exception, it works just fine.
>
> So, you throw an exception back over:
>
> void foo() throw () ;
>
> Or you call unexpected()? Or what?
>
> You don't have any right to propagate an exception through a call to foo
> without breaking the C++ model, and you don't have a C++ program flow
> facility other than exceptions to allow you to do the stack unwind in
> this way.

My first comment echos your final comment, "It's not C++". Absolutely.
The whole problem is that there's no formal (or even widely agreed)
coordination between C++ semantics and POSIX thread semantics. That's
what I've been saying all along. This is too bad, but, so what? I doubt
that this the first time you've lived beyond the strict boundary of a
standard.

Next, while cancellation on Digital UNIX is represented by an exception,
it is NOT a C++ exception, and does not interact with the C++ exception
model. It is not possible for a DEC C++ program to "throw cancel()", nor
can it "catch (cancel)". However, because the DEC C++ runtime and the
POSIX thread runtime both use the underlying "native" exceptions, the
DEC C++ runtime is able to run destructors on ANY exit from a block,
including a non-C++ exception.

Finally, I would argue that, in a C++ programming model that properly
recognized threads, your example of "void foo() throw ();" would be in
error. If foo() is a cancellation point (and it is a cancellation point
if it calls anything that is a cancellation point), then, if there were
a C++ cancellation exception, it would be illegal for foo() to fail to
include that exception in its throw clause. That's the entire purpose
for having a throw clause as part of a function specification!

> I'm not sure I'm with you on whether pthread_cancel does otherwise that
> 'stop a thread dead' with the specific exception of the cancellation
> handlers
> as in:
>

> >That (the last part) doesn't follow, because there's no concept of
> >"stopping a thread dead" in POSIX. And, if there were, it would have
> >nothing to do with cancellation. The whole point of cancellation is that
>

> The text for pthread_cancel says 'When the cancellation is acted on, the
> cancellation cleanup handlers for the thread are called. When the last
> cancellation cleanup handler returns, the thread-specific data
> destructor
> functions shall be called for thread. When the last destructor function
> returns, thread shall be terminated.'

I guess that depends on what you mean by "stop dead". If my explanation
and the POSIX semantics for cancellation cleanup fit your definition of
"stop dead", then, fine, cancellation stops the thread dead. However, I
think that's a peculiar definition of "stop dead". My expectation from
the phrase is more along the lines of the Win32 "terminate thread"
function -- you call it, the thread's gone. Period. No cleanup, no
control.

> This doesn't entirely square with performing any other actions, such as
> unwinding stacks - the cleanup handlers and destructor functions in this
> case are explicit pthread entities. If your C++ implementation chooses
> to link stack contexts into this framework then that's clearly an
> extension.

An extension to what? C++ doesn't exist in POSIX, and POSIX threads
don't exist in C++. How exactly do you define "extension" in this
context? POSIX cleanup handlers were SPECIFICALLY designed so that they
could be implemented using "native exception handling" where that was
possible. This was done specifically because we already did it that way,
we intended to keep doing it that way, and it made absolutely no sense
to anyone else to prevent us from doing it that way. (Regardless of the
fact that some members of the working group initially didn't like the
idea of cancellation and cleanup handlers, once it was accepted nobody
ever said that it ought to be specified in such a way as to prevent an
implementation based on exceptions.) ANSI C, of course, has no concept
of exceptions, and POSIX doesn't recognize C++. The primitive
description of cleanup handlers in POSIX therefore obviously couldn't
say "exceptions". POSIX doesn't really say anything about "kernel
threads" or much about 2 level scheduling, either. That doesn't (and
shouldn't) stop anyone from using them.

> Its not C++.

Right. So what's your point? :-) There are probably a LOT of things you
use in your C++ programs that "aren't C++". It's not exactly a
self-contained language. One could argue that it's illegal and
unreasonable to use threads in a C++ program because the standards don't
recognize each other -- but that would be pretty silly. And, in fact,
most vendors' implementations of C++ and threads should, as time passes,
be expected to make them work together "reasonably well". Perhaps
eventually there will even be some standard at least encouraging, if not
mandating, this. Until then, be cautious, but don't hesitate to use C++
and threads together where it makes sense.

James Mansion

unread,
May 12, 1997, 3:00:00 AM5/12/97
to

Dave Butenhof wrote:

> Finally, I would argue that, in a C++ programming model that properly
> recognized threads, your example of "void foo() throw ();" would be in
> error. If foo() is a cancellation point (and it is a cancellation point
> if it calls anything that is a cancellation point), then, if there were
> a C++ cancellation exception, it would be illegal for foo() to fail to
> include that exception in its throw clause. That's the entire purpose
> for having a throw clause as part of a function specification!

Well, I think we are agreed, except that I would argue strongly that
cancellation should NOT be used in a C++ program, which gets around this
particular nasty.

Really, cancellation is so fraught with danger that it seems unwise to
use
it unless you absolutely have to. I'd not want to try creating a test
plan
for a system that used it, for a start.

In the case of the example I posted I think that the DEc C++ behaviour
is NOT
what I want. If I write that signature then I can a contract that says
that
the control flow doesn't come back out of the function unless its the
normal
flow and I'd rather the process bombed. Doing otherwise opens too big a
can or worms.

> > This doesn't entirely square with performing any other actions, such as
> > unwinding stacks - the cleanup handlers and destructor functions in this
> > case are explicit pthread entities. If your C++ implementation chooses
> > to link stack contexts into this framework then that's clearly an
> > extension.
>
> An extension to what? C++ doesn't exist in POSIX, and POSIX threads
> don't exist in C++. How exactly do you define "extension" in this
> context? POSIX cleanup handlers were SPECIFICALLY designed so that they

Fine, we know we are in never-never land. But there are people here who
are discussing this issue as a 'quality of implementation' issue, which
it isn't really.

I grant that translating asynch events such as a cancellation into an
exception (whether a C++ one or some low level cruft that can cause
similar
behaviours) can be useful, you get very platform dependent very
quickly. But heck, who said Open Systems meant portability anyway? ;-)

> Right. So what's your point? :-) There are probably a LOT of things you
> use in your C++ programs that "aren't C++". It's not exactly a
> self-contained language. One could argue that it's illegal and
> unreasonable to use threads in a C++ program because the standards don't
> recognize each other -- but that would be pretty silly. And, in fact,
> most vendors' implementations of C++ and threads should, as time passes,
> be expected to make them work together "reasonably well". Perhaps
> eventually there will even be some standard at least encouraging, if not
> mandating, this. Until then, be cautious, but don't hesitate to use C++
> and threads together where it makes sense.

Sure. Indeed its my business. But it remains to be seen whether the
integrated low-level exception handling approach is the 'best'. Its
not an accident that the VC++ default behaviour changed with v5 for
instance.

All I would ask for in the short term is some reassurance, preferably in
an addendum to the C++ standard, that within the body of a thread in C++
the code behaves 'as if' it were the main thread in a single threaded
program.

Even that is absent at present.

>
> /---[ Dave Butenhof ]-----------------------[ bute...@zko.dec.com ]---\
> | Digital Equipment Corporation 110 Spit Brook Rd ZKO2-3/Q18 |
> | 603.881.2218, FAX 603.881.0120 Nashua NH 03062-2698 |
> \-----------------[ Better Living Through Concurrency ]----------------/

--

0 new messages