public inbox for pthreads-win32@sourceware.org
 help / color / mirror / Atom feed
* pthreads VCE: problem with destructor
@ 2001-01-05  8:30 Gardian, Milan
  2001-12-18  6:18 ` Gardian, Milan
  0 siblings, 1 reply; 32+ messages in thread
From: Gardian, Milan @ 2001-01-05  8:30 UTC (permalink / raw)
  To: Pthreads-Win32@Sources.Redhat.Com; +Cc: Ross Johnson (E-mail)

Hi,

I came across a problem with pthreads VCE: destructors for objects in local
scope (automatic variables on stack) of the thread-function are not called
when using 'pthread_exit' to exit the thread (or when using any function
that eventually throws a C++ exception (because of VCE build) using
ptw32_throw internal function).

To illustrate this point I created a new test case, 'exit4.c'. It uses a C++
guard object to increment a shared reference count in constructor and
decrement it in destructor. This object is then created on stack in both the
main thread (before creating the new thread) and in the thread-function
(i.e. reference count is increased by 2).

If we finish the thread-function by returning from it (falling off the end),
destructor for both objects is called as expected (first the thread-function
local object and then the main thread local object). This case is
illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line 11
-> the test case passes.

On the other hand if we finish the thread-function by using 'pthread_exit'
instead of falling off the end, the destructor for the thread-function local
object is NOT called (although the destructor for main thread local object
is called). This case is illustrated by compiling with the macro
USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.

C++ resource idiom (acquire in constructor, release in destructor) is used
throughout our threaded program. The described behaviour of pthreads is
introducing possibility of a resource leak and potential deadlock. Does
anybody have any ideas what is happening and how to resolve the problem?

Thank you very much for your replies and help,

Cheers,

	Milan


PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
17-DEC-2001 by Ross)

PS1: Note that the reference counting need not be protected by a mutex as it
will never be accessed simultaneously by both threads due to synchronization
using pthread_join.

PS2: The exit4.c file
===================================
/*
 * Test for pthread_exit().
 *
 * Depends on API functions: pthread_create().
 */

#include "test.h"

#ifdef __cplusplus

#define USE_PTHREAD_EXIT
static const int init_counter_value = 3;
static void *ret_value = reinterpret_cast<void *>(1);
static int counter = init_counter_value;

class Guard
{
    const char * const _str;
    int &_ref;
    Guard &operator=(const Guard&);
    Guard(const Guard&);
public:
    Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
        printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
    };
    ~Guard() {
        printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
    };
};


void *
func(void * arg)
{
    Guard g("func", counter);
#ifdef USE_PTHREAD_EXIT
    pthread_exit(arg);
    assert(0); //Never reached with pthread_exit
#endif //USE_PTHREAD_EXIT
    return ret_value;
}


#endif /*__cplusplus */

int main(int, char **)
{
#ifndef __cplusplus
    printf("Test requires C++. Skipped.\n");
#else
    {
        void *ret = 0;
        Guard g("main", counter);
        pthread_t id;
        assert(0 == pthread_create(&id, 0, func, ret_value));
        assert(0 == pthread_join(id, &ret));
        assert(ret == ret_value);
    }
    assert(counter == init_counter_value);
#endif /*__cplusplus */
    return 0;
}
===================================


PS3: Changes to the 'tests/Makefile' (diff file, use patch):
===================================
--- ..\..\pthreads\tests\Makefile	Fri Oct 26 12:12:48 2001
+++ Makefile	Tue Dec 18 14:16:00 2001
@@ -41,7 +41,7 @@
 	  mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass  mutex2.pass
mutex3.pass  \
 	  condvar1.pass  condvar2.pass  condvar2_1.pass  \
 	  exit1.pass  create1.pass  equal1.pass  \
-	  exit2.pass  exit3.pass  \
+	  exit2.pass  exit3.pass exit4.pass \
 	  join0.pass  join1.pass  join2.pass  \
 	  mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass  mutex6r.pass
\
 	  count1.pass  once1.pass  tsd1.pass  \
@@ -186,6 +186,7 @@
 exit1.pass:
 exit2.pass: create1.pass
 exit3.pass: create1.pass
+exit4.pass: create1.pass
 eyal1.pass: tsd1.pass
 inherit1.pass: join1.pass
 join0.pass: create1.pass
===================================

^ permalink raw reply	[flat|nested] 32+ messages in thread

* pthreads VCE: problem with destructor
  2001-01-05  8:30 pthreads VCE: problem with destructor Gardian, Milan
@ 2001-12-18  6:18 ` Gardian, Milan
  0 siblings, 0 replies; 32+ messages in thread
From: Gardian, Milan @ 2001-12-18  6:18 UTC (permalink / raw)
  To: Pthreads-Win32@Sources.Redhat.Com; +Cc: Ross Johnson (E-mail)

Hi,

I came across a problem with pthreads VCE: destructors for objects in local
scope (automatic variables on stack) of the thread-function are not called
when using 'pthread_exit' to exit the thread (or when using any function
that eventually throws a C++ exception (because of VCE build) using
ptw32_throw internal function).

To illustrate this point I created a new test case, 'exit4.c'. It uses a C++
guard object to increment a shared reference count in constructor and
decrement it in destructor. This object is then created on stack in both the
main thread (before creating the new thread) and in the thread-function
(i.e. reference count is increased by 2).

If we finish the thread-function by returning from it (falling off the end),
destructor for both objects is called as expected (first the thread-function
local object and then the main thread local object). This case is
illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line 11
-> the test case passes.

On the other hand if we finish the thread-function by using 'pthread_exit'
instead of falling off the end, the destructor for the thread-function local
object is NOT called (although the destructor for main thread local object
is called). This case is illustrated by compiling with the macro
USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.

C++ resource idiom (acquire in constructor, release in destructor) is used
throughout our threaded program. The described behaviour of pthreads is
introducing possibility of a resource leak and potential deadlock. Does
anybody have any ideas what is happening and how to resolve the problem?

Thank you very much for your replies and help,

Cheers,

	Milan


PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
17-DEC-2001 by Ross)

PS1: Note that the reference counting need not be protected by a mutex as it
will never be accessed simultaneously by both threads due to synchronization
using pthread_join.

PS2: The exit4.c file
===================================
/*
 * Test for pthread_exit().
 *
 * Depends on API functions: pthread_create().
 */

#include "test.h"

#ifdef __cplusplus

#define USE_PTHREAD_EXIT
static const int init_counter_value = 3;
static void *ret_value = reinterpret_cast<void *>(1);
static int counter = init_counter_value;

class Guard
{
    const char * const _str;
    int &_ref;
    Guard &operator=(const Guard&);
    Guard(const Guard&);
public:
    Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
        printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
    };
    ~Guard() {
        printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
    };
};


void *
func(void * arg)
{
    Guard g("func", counter);
#ifdef USE_PTHREAD_EXIT
    pthread_exit(arg);
    assert(0); //Never reached with pthread_exit
#endif //USE_PTHREAD_EXIT
    return ret_value;
}


#endif /*__cplusplus */

int main(int, char **)
{
#ifndef __cplusplus
    printf("Test requires C++. Skipped.\n");
#else
    {
        void *ret = 0;
        Guard g("main", counter);
        pthread_t id;
        assert(0 == pthread_create(&id, 0, func, ret_value));
        assert(0 == pthread_join(id, &ret));
        assert(ret == ret_value);
    }
    assert(counter == init_counter_value);
#endif /*__cplusplus */
    return 0;
}
===================================


PS3: Changes to the 'tests/Makefile' (diff file, use patch):
===================================
--- ..\..\pthreads\tests\Makefile	Fri Oct 26 12:12:48 2001
+++ Makefile	Tue Dec 18 14:16:00 2001
@@ -41,7 +41,7 @@
 	  mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass  mutex2.pass
mutex3.pass  \
 	  condvar1.pass  condvar2.pass  condvar2_1.pass  \
 	  exit1.pass  create1.pass  equal1.pass  \
-	  exit2.pass  exit3.pass  \
+	  exit2.pass  exit3.pass exit4.pass \
 	  join0.pass  join1.pass  join2.pass  \
 	  mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass  mutex6r.pass
\
 	  count1.pass  once1.pass  tsd1.pass  \
@@ -186,6 +186,7 @@
 exit1.pass:
 exit2.pass: create1.pass
 exit3.pass: create1.pass
+exit4.pass: create1.pass
 eyal1.pass: tsd1.pass
 inherit1.pass: join1.pass
 join0.pass: create1.pass
===================================

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
  2001-03-22 11:41 Bossom, John
@ 2001-12-20  8:46 ` Bossom, John
  0 siblings, 0 replies; 32+ messages in thread
From: Bossom, John @ 2001-12-20  8:46 UTC (permalink / raw)
  To: 'Alexander Terekhov', pthreads-win32

A well respected opinion, indeed, given he (David Butenhof) is
the author of "Programming with POSIX Threads". 

However, this is an opinion.... it is not reality today. And demanding
a free, open-source, library that was attempting to provide a portable
solution for PTHREADs for win32 developers would lull C++ developers
into a false sense of security and will get a very rude shock when/if
they port their product to UNIX.

As I have already stated, if you base your code on
a non-standard implementation "today", then you are asking for trouble
if you intended on your code to be portable. Even if you demand
this change now, just when do you think you are actually going
to get a portable solution that you can actually use and depend
upon?

I, for one, will not tell my company that we cannot release
a product on all platforms because I am waiting for the POSIX 
and C++ standards committee to comply with my request (then waiting
(possibly years) for the OS implementors to adopt the "new" standard) --- 
I would be out of a job.




-----Original Message-----
From: Alexander Terekhov [ mailto:TEREKHOV@de.ibm.com ]
Sent: December 20, 2001 9:09 AM
To: pthreads-win32@sources.redhat.com
Subject: Re: pthreads VCE: problem with destructor



> Please do not take my comments out of the context. The original text was
[...]
> I do not wanted the destructors to be run because this is nonportable.
> Before the setjmp/longjmp code the only working implementation for
> mingw32 was the c++ one that i disliked.

OK, just one more try...

Consider the following opinion:

http://groups.google.com/groups?as_umsgid=3A8D120B.73749CEC%40compaq.com

"In any RATIONAL and USEFUL implementation that supports both POSIX threads
and
 C++, there's no different between "calling POSIX cleanup handlers" and
 "throwing a C++ exception", because thread cancellation and exit, and C++
 exceptions, are all instances of an underlying universal platform
exception
 infrastructure. That means that POSIX cleanup handlers will be run when a
 thrown C++ exception propagates through the frame in which the cleanup
handler
 has been pushed; and C++ object destructors will be run when a local
object is
 active in a frame through which a POSIX cancellation or exit propagates.

 The same, of course, must be true for any other language with exceptions
and
 handlers.

 Either the "system" is a "system", or it's a collection of spare parts
that
 happen to have been dumped in the same box. The latter may not explicitly
 violate any standards, and may even be usable with sufficient effort and
 restrictions; but that doesn't make it a good idea.

 System implementors should get this right. Application developers should
 demand it. The days are long gone when exceptions were some arcane thing
that
 only a few weird and non-mainstream languages supported. For a system to
work,
 exceptions must be integrated into the system's basic calling standard
along
 with issues like register usage and the appearance of stack frames.
There's
 simply no excuse for messing this up, and no excuses should be accepted!

 /------------------[ David.Butenhof@compaq.com ]------------------\
 | Compaq Computer Corporation              POSIX Thread Architect |
 |     My book: http://www.awl.com/cseng/titles/0-201-63392-2/     |
 \-----[ http://home.earthlink.net/~anneart/family/dave.html ]-----/"

regards,
alexander.


This message may contain privileged and/or confidential information.  If you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender by
e-mail promptly that you have done so.  Thank You.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-03-22 11:39 Alexander Terekhov
@ 2001-12-20  6:08 ` Alexander Terekhov
  0 siblings, 0 replies; 32+ messages in thread
From: Alexander Terekhov @ 2001-12-20  6:08 UTC (permalink / raw)
  To: pthreads-win32

> Please do not take my comments out of the context. The original text was
[...]
> I do not wanted the destructors to be run because this is nonportable.
> Before the setjmp/longjmp code the only working implementation for
> mingw32 was the c++ one that i disliked.

OK, just one more try...

Consider the following opinion:

http://groups.google.com/groups?as_umsgid=3A8D120B.73749CEC%40compaq.com

"In any RATIONAL and USEFUL implementation that supports both POSIX threads
and
 C++, there's no different between "calling POSIX cleanup handlers" and
 "throwing a C++ exception", because thread cancellation and exit, and C++
 exceptions, are all instances of an underlying universal platform
exception
 infrastructure. That means that POSIX cleanup handlers will be run when a
 thrown C++ exception propagates through the frame in which the cleanup
handler
 has been pushed; and C++ object destructors will be run when a local
object is
 active in a frame through which a POSIX cancellation or exit propagates.

 The same, of course, must be true for any other language with exceptions
and
 handlers.

 Either the "system" is a "system", or it's a collection of spare parts
that
 happen to have been dumped in the same box. The latter may not explicitly
 violate any standards, and may even be usable with sufficient effort and
 restrictions; but that doesn't make it a good idea.

 System implementors should get this right. Application developers should
 demand it. The days are long gone when exceptions were some arcane thing
that
 only a few weird and non-mainstream languages supported. For a system to
work,
 exceptions must be integrated into the system's basic calling standard
along
 with issues like register usage and the appearance of stack frames.
There's
 simply no excuse for messing this up, and no excuses should be accepted!

 /------------------[ David.Butenhof@compaq.com ]------------------\
 | Compaq Computer Corporation              POSIX Thread Architect |
 |     My book: http://www.awl.com/cseng/titles/0-201-63392-2/     |
 \-----[ http://home.earthlink.net/~anneart/family/dave.html ]-----/"

regards,
alexander.


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-03-22 11:19 Thomas Pfaff
@ 2001-12-20  4:40 ` Thomas Pfaff
  0 siblings, 0 replies; 32+ messages in thread
From: Thomas Pfaff @ 2001-12-20  4:40 UTC (permalink / raw)
  To: TEREKHOV; +Cc: pthreads-win32

> > This is exactly the reason why i have created the
> > setjmp/longjmp version.
>
> I am really puzzled. Since there is no standard
> PTHREAD C++ bindings that would guarantee things
> such as C++ tack unwinding on thread exit/
> cancellation, any C++ threaded written to exploit
> such things is NOT truly portable. However, there
> is practically no way to make thread cancellation/
> exit work in C++ programs using setjmp/longjmp
> because the C++ standard restricts the LEGAL
> usage of longjmp in *C++* programs:
>
> ISO/IEC 14882:1998(E), Pg 347:
>
> "The function signature longjmp(jmp_buf jbuf, int val)
>  has more restricted behavior in this International
>  Standard. If any automatic objects would be destroyed
>  by a thrown exception transferring control to another
>  (destination) point in the program, then a call to
>  longjmp( jbuf, val) at the throw point that transfers
>  control to the same (destination) point has
>  undefined behavior."
>  ^^^^^^^^^^^^^^^^^^
>
> regards,
> alexander.


Please do not take my comments out of the context. The original text was

*****
> Regardless as Mr. Bossom so well has already stated: I certainly
> wouldn't
> depend on pthread_exit() or pthread_cancel() allowing destructors to run
> to be
> portable though.  Since the primary purpose of this library is to
> enhance
> portability of programs using pthreads, counting on pthread_exit() or
> pthread_cancel() to work in a non-portable way seems self-defeating.

This is exactly the reason why i have created the setjmp/longjmp version.
There may be bugs in it but i think they could be discovered if more would
using it.
*****

I do not wanted the destructors to be run because this is nonportable.
Before the setjmp/longjmp code the only working implementation for
mingw32 was the c++ one that i disliked.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-03-12  5:53 Alexander Terekhov
@ 2001-12-20  2:35 ` Alexander Terekhov
  0 siblings, 0 replies; 32+ messages in thread
From: Alexander Terekhov @ 2001-12-20  2:35 UTC (permalink / raw)
  To: pthreads-win32

>> Since the primary purpose of this library is to
>> enhance portability of programs using pthreads,
>> counting on pthread_exit() or pthread_cancel()
>> to work in a non-portable way seems self-defeating.

Well, you are certainly allowed NOT to use pthread_exit()
and pthread_cancel() in your C++ programs. As long as
implementation invokes C thread cleanup handlers *IN C*
programs IT IS CONFORMING.

Why do you care how pthread library for C++ implements
it wrt to C++ stack unwinding? As long as you are not
using it (_cancel/_exit) that should not be an issue
for you.

> This is exactly the reason why i have created the
> setjmp/longjmp version.

I am really puzzled. Since there is no standard
PTHREAD C++ bindings that would guarantee things
such as C++ tack unwinding on thread exit/
cancellation, any C++ threaded written to exploit
such things is NOT truly portable. However, there
is practically no way to make thread cancellation/
exit work in C++ programs using setjmp/longjmp
because the C++ standard restricts the LEGAL
usage of longjmp in *C++* programs:

ISO/IEC 14882:1998(E), Pg 347:

"The function signature longjmp(jmp_buf jbuf, int val)
 has more restricted behavior in this International
 Standard. If any automatic objects would be destroyed
 by a thrown exception transferring control to another
 (destination) point in the program, then a call to
 longjmp( jbuf, val) at the throw point that transfers
 control to the same (destination) point has
 undefined behavior."
 ^^^^^^^^^^^^^^^^^^

regards,
alexander.


Thomas Pfaff <tpfaff@gmx.net>@sources.redhat.com on 12/20/2001 10:25:14 AM

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
cc:
Subject:  Re: pthreads VCE: problem with destructor




On Wed, 19 Dec 2001, reentrant wrote:

>
> Due to the nature of the beast just as the responsibility lies with the
> programmer to design the program to "cleanly" (including running
> destructors,
> ad nauseum) exit when exit() is called, it should also be the
> responsibility of
> the programmer to design a thread to cleanly exit with pthread_exit() or
> pthread_cancel() are called.  Just as exit() should not be called in a
> C++
> program if dtors are desired to run neither should pthread_exit() from a
> thread.  IMHO.
>
> I would imagine that exit() was chosen not to be modified to account for
> running C++ destructors for about the same reasons that pthread_exit()
> should
> not account for running C++ destructors.  Dtors not being called in
> these cases
> is and should be expected behavior.
>
> Regardless as Mr. Bossom so well has already stated: I certainly
> wouldn't
> depend on pthread_exit() or pthread_cancel() allowing destructors to run
> to be
> portable though.  Since the primary purpose of this library is to
> enhance
> portability of programs using pthreads, counting on pthread_exit() or
> pthread_cancel() to work in a non-portable way seems self-defeating.

This is exactly the reason why i have created the setjmp/longjmp version.
There may be bugs in it but i think they could be discovered if more would
using it.


> While attempting to allow dtors to be run upon a pthread_exit() or
> pthread_cancel() is certainly a noble goal, it's beyond the scope of the
> pthread library.  It's the programmer's responsibility IMHO.
>
> So, as I hope is obvious by this point :), I am completely in support of
> the
> "nasty hacks" being removed and a clean C interface version of the
> library
> being provided only.

Try the GC stuff and report bugs.

>
> My two cents,
> Dave
>
>
> --- Ross Johnson <rpj@ise.canberra.edu.au> wrote:
> > I sense a rising and ruthless desire to deal with the problem of
> > the exception-based versions of the library. It would certainly
> > be a lot easier if they weren't there, and there are some
> > hacks in pthread.h supporting them that really are nasty.
> >
> > So ... what to do about them?
> >
> > I will firstly put John's warning in the README file
> > and the README.NONPORTABLE file, and on the Web page.
> >
> > Secondly, there is a standard C version of the library courtesy
> > of Thomas Pfaff's contributions. It uses setjmp/longjmp.
> > Does this need to be built differently to work with C++
> > applications (assuming they are written as John suggests they
> > should be)?

No. The only thing you need is to define __CLEANUP_C to avoid the default
handling in pthread.h.

/*
 * define defaults for cleanup code
 */
#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined(
__CLEANUP_C )

#if defined(_MSC_VER)
#define __CLEANUP_SEH
#elif defined(__cplusplus)
#define __CLEANUP_CXX
#else
#define __CLEANUP_C
#endif

#endif

These defaults have been added to be backward compatible and it is time to
remove them.


> > I can try putting it through the VCE run of the
> > test suite as soon as I reinstall my corrupted Windows 98 machine.
> >
> > Thirdly, if possible, consider phasing out all but the VC and GC
> > versions of the library (currently the only standard C versions).
> > That is, phase out the VCE, VSE, and GCE versions.
> >
> > Does anyone wan't to jump up and shout - NO!!
> >
> > Ross
> >
>

Regards,
Thomas




^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-03-10  6:41     ` Thomas Pfaff
@ 2001-12-20  1:25       ` Thomas Pfaff
  0 siblings, 0 replies; 32+ messages in thread
From: Thomas Pfaff @ 2001-12-20  1:25 UTC (permalink / raw)
  To: Pthreads-Win32@Sources.Redhat.Com

On Wed, 19 Dec 2001, reentrant wrote:

>
> Due to the nature of the beast just as the responsibility lies with the
> programmer to design the program to "cleanly" (including running
> destructors,
> ad nauseum) exit when exit() is called, it should also be the
> responsibility of
> the programmer to design a thread to cleanly exit with pthread_exit() or
> pthread_cancel() are called.  Just as exit() should not be called in a
> C++
> program if dtors are desired to run neither should pthread_exit() from a
> thread.  IMHO.
>
> I would imagine that exit() was chosen not to be modified to account for
> running C++ destructors for about the same reasons that pthread_exit()
> should
> not account for running C++ destructors.  Dtors not being called in
> these cases
> is and should be expected behavior.
>
> Regardless as Mr. Bossom so well has already stated: I certainly
> wouldn't
> depend on pthread_exit() or pthread_cancel() allowing destructors to run
> to be
> portable though.  Since the primary purpose of this library is to
> enhance
> portability of programs using pthreads, counting on pthread_exit() or
> pthread_cancel() to work in a non-portable way seems self-defeating.

This is exactly the reason why i have created the setjmp/longjmp version.
There may be bugs in it but i think they could be discovered if more would
using it.


> While attempting to allow dtors to be run upon a pthread_exit() or
> pthread_cancel() is certainly a noble goal, it's beyond the scope of the
> pthread library.  It's the programmer's responsibility IMHO.
>
> So, as I hope is obvious by this point :), I am completely in support of
> the
> "nasty hacks" being removed and a clean C interface version of the
> library
> being provided only.

Try the GC stuff and report bugs.

>
> My two cents,
> Dave
>
>
> --- Ross Johnson <rpj@ise.canberra.edu.au> wrote:
> > I sense a rising and ruthless desire to deal with the problem of
> > the exception-based versions of the library. It would certainly
> > be a lot easier if they weren't there, and there are some
> > hacks in pthread.h supporting them that really are nasty.
> >
> > So ... what to do about them?
> >
> > I will firstly put John's warning in the README file
> > and the README.NONPORTABLE file, and on the Web page.
> >
> > Secondly, there is a standard C version of the library courtesy
> > of Thomas Pfaff's contributions. It uses setjmp/longjmp.
> > Does this need to be built differently to work with C++
> > applications (assuming they are written as John suggests they
> > should be)?

No. The only thing you need is to define __CLEANUP_C to avoid the default
handling in pthread.h.

/*
 * define defaults for cleanup code
 */
#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined(
__CLEANUP_C )

#if defined(_MSC_VER)
#define __CLEANUP_SEH
#elif defined(__cplusplus)
#define __CLEANUP_CXX
#else
#define __CLEANUP_C
#endif

#endif

These defaults have been added to be backward compatible and it is time to
remove them.


> > I can try putting it through the VCE run of the
> > test suite as soon as I reinstall my corrupted Windows 98 machine.
> >
> > Thirdly, if possible, consider phasing out all but the VC and GC
> > versions of the library (currently the only standard C versions).
> > That is, phase out the VCE, VSE, and GCE versions.
> >
> > Does anyone wan't to jump up and shout - NO!!
> >
> > Ross
> >
>

Regards,
Thomas

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
  2001-02-23  8:35 Bossom, John
@ 2001-12-19 13:19 ` Bossom, John
  0 siblings, 0 replies; 32+ messages in thread
From: Bossom, John @ 2001-12-19 13:19 UTC (permalink / raw)
  To: 'Alexander Terekhov', pthreads-win32

Well I am sure we all wish for that functionality, don't hold your breath
waiting on Sun Microsystems,HP, IBM, etc. Unix providers supplying this
functionality. (i.e. C++ working in tandem with pthread_cancel or any
other C based functionality for that matter (i.e. longjmp/setjmp, signal
handling, etc)

It wasn't there 3.5 years ago when I came up with the initial pthreads
source code that I contributed to the pthreads-win32.

Putting such functionality into pthreads-win32 would mean that any
code leveraging it will not port to platforms that actually provide
pthreads libraries.

The book "Multithreaded Programming with PTHREADS", by Bil Lewis
and Daniel J. Berg, pages 232-233 gives an overview of the issues
in using C++ and PThreads together. 

I feel your pain (I've been there already)

Sincerely,

John.


-----Original Message-----
From: Alexander Terekhov [ mailto:TEREKHOV@de.ibm.com ]
Sent: December 19, 2001 2:03 PM
To: pthreads-win32@sources.redhat.com
Subject: RE: pthreads VCE: problem with destructor




> Alexander, it is not clear to me what you are strongly disagreeing
> with... my recommendation? (and it is not solely my recommendation,
> I can quote oodles of books recommending the same approach)

Yes.

> However, pthread_cancel is not documented as working in
> tandem with C++ stack unwinding.

I believe that it should be documented that a version
of pthreads-win32 library meant to be used in C++ programs
DOES work in tandem with C++ stack unwinding. Note that it
has nothing to do with a version of pthreads-win32 library
meant to be used in pure C programs.

> I would not recommend using it in a C++ application.

Personally, I disagree strongly with this approach.
I would ask pthread-lib vendor to provide C++ aware
pthread library, instead.

> To deal with "cancel",
> I would recommend representing a unit of work (i.e. a task)
> as an object that supports it's own ability to "cancel".
> A thread is just a means to an end... you want to do
> a unit of work. A unit of work could be executed directly,
> or within a thread, or tasked through a thread pool. The
> easiest, consistent, method of cancelling it is to cancel
> the task, not the "worker" trying to do the task.

Jobs/Tasks are OK, but they are not threads.
pthread_cancel and _exit are designed for threads.

> The only advantage that pthread_cancel has (on unix, that is)
> is that some basic C library methods that block are cancellable
> by pthread_cancel. You don't have this luxury on win32 unless you
> re-write the C runtime library with pthreads-win32.

Well, for example, how about waiting on condition
variable? That is a cancellation point that works
even with pthreads-win32. I do not want to replace
it with modified predicates which would include
"me->canceled()" flag. I do not want to know which
mutexes need to be locked and which condition variables
need to be signaled/broadcasted for a particular thread
to archive the effect meant to be provided by the
pthread_cancel.

I just want that in addition to C thread cleanup
handlers, thread cancel/exit would invoke C++
destructors and "catch(...)" handlers.

regards,
alexander.


"Bossom, John" <John.Bossom@Cognos.COM>@sources.redhat.com on 12/19/2001
03:00:58 PM

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   Alexander Terekhov/Germany/IBM@IBMDE,
      pthreads-win32@sources.redhat.com
cc:
Subject:  RE: pthreads VCE: problem with destructor



Alexander, it is not clear to me what you are strongly disagreeing
with... my recommendation? (and it is not solely my recommendation,
I can quote oodles of books recommending the same approach)

However, pthread_cancel is not documented as working in
tandem with C++ stack unwinding. I would not recommend
using it in a C++ application.

To deal with "cancel",
I would recommend representing a unit of work (i.e. a task)
as an object that supports it's own ability to "cancel".
A thread is just a means to an end... you want to do
a unit of work. A unit of work could be executed directly,
or within a thread, or tasked through a thread pool. The
easiest, consistent, method of cancelling it is to cancel
the task, not the "worker" trying to do the task.
The only advantage that pthread_cancel has (on unix, that is)
is that some basic C library methods that block are cancellable
by pthread_cancel. You don't have this luxury on win32 unless you
re-write the C runtime library with pthreads-win32.

Just my 2 cents.

Good Luck,

John.


-----Original Message-----
From: Alexander Terekhov [ mailto:TEREKHOV@de.ibm.com ]
Sent: December 19, 2001 7:41 AM
To: pthreads-win32@sources.redhat.com
Subject: Re: pthreads VCE: problem with destructor



> > Recommended approach when using C++ in conjunction with pthreads is to
> > NEVER use pthread_exit... you should have your code return to your
> > thread mainline (use exceptions if you choose) and simply "return"
> > from the thread mainline.

How about pthread_cancel? Are you saying that I should
never use it in a threaded C++ program for the same
reason(s) as pthread_exit?

Personally, I disagree strongly with this approach.

FYI:

http://groups.google.com/groups?as_umsgid=362DCB0D.230D900%40zko.dec.com
http://groups.google.com/groups?as_umsgid=kZ7h7.623%24bB1.30401%40news.cpqco

rp.net
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0004.HTM#cancel_excep_sec
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0001.HTM#index_x_53

"Several Threads Library features and most Threads Library
 identifiers are provided as C language macros. As such,
 their definitions may not be available in other languages.
 Developers working in other languages will have to provide
 their own declarations of functions and constants, and
 features such as TRY/CATCH exception handling and POSIX
 push/pop cleanup handlers may be completely unavailable
 (although it may be possible to provide similar
 functionality using native exception handling facilities).
 Note that in this context, C++ is a non-C language;
 while the C language macros may compile successfully
 under C++, TRY/CATCH and push/pop cleanup handlers
 are not supported for C++ code. C++ code should use
 object descructors and C++ exception handlers. "
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0011.HTM#excep_defs

"Exception         Definition
 ================  ===================================
 pthread_cancel_e  Thread cancelation in progress
 .
 .
 .
 pthread_exit_e    Thread exiting using pthread_exit()"

regards,
alexander.


Ross Johnson <rpj@ise.canberra.edu.au>@sources.redhat.com on 12/19/2001
12:37:59 PM

Please respond to rpj@ise.canberra.edu.au

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Bossom, John" <John.Bossom@Cognos.COM>
cc:   "'Gardian, Milan'" <Milan.Gardian@LEIBINGER.com>,
      "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
Subject:  Re: pthreads VCE: problem with destructor



I sense a rising and ruthless desire to deal with the problem of
the exception-based versions of the library. It would certainly
be a lot easier if they weren't there, and there are some
hacks in pthread.h supporting them that really are nasty.

So ... what to do about them?

I will firstly put John's warning in the README file
and the README.NONPORTABLE file, and on the Web page.

Secondly, there is a standard C version of the library courtesy
of Thomas Pfaff's contributions. It uses setjmp/longjmp.
Does this need to be built differently to work with C++
applications (assuming they are written as John suggests they
should be)? I can try putting it through the VCE run of the
test suite as soon as I reinstall my corrupted Windows 98 machine.

Thirdly, if possible, consider phasing out all but the VC and GC
versions of the library (currently the only standard C versions).
That is, phase out the VCE, VSE, and GCE versions.

Does anyone wan't to jump up and shout - NO!!

Ross

"Bossom, John" wrote:
>
> <Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)
>
> You are entering dark territory here. You are assuming that
> Operating System primitives actually cooperate with C++ primitives (i.e
> exception handling, implicit
> call of local destructors)
> This is not the case. At the time of implementation of pthread_win32
> (original version) pthread_exit on UNIX did NOT call the C++ destructors
> and perform graceful stack unwinding. pthread_exit basically did an end
run
> exit and locally called all registered pthread cleanup methods.
>
> Recommended approach when using C++ in conjunction with pthreads is to
> NEVER use pthread_exit... you should have your code return to your
> thread mainline (use exceptions if you choose) and simply "return"
> from the thread mainline.
>
> If you (Ross) implement this marrying of C++ stack-unwinding with
> pthread_exit, I suggest you
> document that it is not typical behavior and you can expect that if you
port
> your code back
> to various unix platforms that actually support pthreads natively, you
> will encounter exactly the same problem.
>
> -----Original Message-----
> From: Gardian, Milan [ mailto:Milan.Gardian@LEIBINGER.com ]
> Sent: December 18, 2001 9:17 AM
> To: Pthreads-Win32@Sources.Redhat.Com
> Cc: Ross Johnson (E-mail)
> Subject: pthreads VCE: problem with destructor
>
> Hi,
>
> I came across a problem with pthreads VCE: destructors for objects in
local
> scope (automatic variables on stack) of the thread-function are not
called
> when using 'pthread_exit' to exit the thread (or when using any function
> that eventually throws a C++ exception (because of VCE build) using
> ptw32_throw internal function).
>
> To illustrate this point I created a new test case, 'exit4.c'. It uses a
C++
> guard object to increment a shared reference count in constructor and
> decrement it in destructor. This object is then created on stack in both
the
> main thread (before creating the new thread) and in the thread-function
> (i.e. reference count is increased by 2).
>
> If we finish the thread-function by returning from it (falling off the
end),
> destructor for both objects is called as expected (first the
thread-function
> local object and then the main thread local object). This case is
> illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line
11
> -> the test case passes.
>
> On the other hand if we finish the thread-function by using
'pthread_exit'
> instead of falling off the end, the destructor for the thread-function
local
> object is NOT called (although the destructor for main thread local
object
> is called). This case is illustrated by compiling with the macro
> USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.
>
> C++ resource idiom (acquire in constructor, release in destructor) is
used
> throughout our threaded program. The described behaviour of pthreads is
> introducing possibility of a resource leak and potential deadlock. Does
> anybody have any ideas what is happening and how to resolve the problem?
>
> Thank you very much for your replies and help,
>
> Cheers,
>
>         Milan
>
> PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
> June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
> 17-DEC-2001 by Ross)
>
> PS1: Note that the reference counting need not be protected by a mutex as
it
> will never be accessed simultaneously by both threads due to
synchronization
> using pthread_join.
>
> PS2: The exit4.c file
> ===================================
> /*
>  * Test for pthread_exit().
>  *
>  * Depends on API functions: pthread_create().
>  */
>
> #include "test.h"
>
> #ifdef __cplusplus
>
> #define USE_PTHREAD_EXIT
> static const int init_counter_value = 3;
> static void *ret_value = reinterpret_cast<void *>(1);
> static int counter = init_counter_value;
>
> class Guard
> {
>     const char * const _str;
>     int &_ref;
>     Guard &operator=(const Guard&);
>     Guard(const Guard&);
> public:
>     Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
>         printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
>     };
>     ~Guard() {
>         printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
>     };
> };
>
> void *
> func(void * arg)
> {
>     Guard g("func", counter);
> #ifdef USE_PTHREAD_EXIT
>     pthread_exit(arg);
>     assert(0); //Never reached with pthread_exit
> #endif //USE_PTHREAD_EXIT
>     return ret_value;
> }
>
> #endif /*__cplusplus */
>
> int main(int, char **)
> {
> #ifndef __cplusplus
>     printf("Test requires C++. Skipped.\n");
> #else
>     {
>         void *ret = 0;
>         Guard g("main", counter);
>         pthread_t id;
>         assert(0 == pthread_create(&id, 0, func, ret_value));
>         assert(0 == pthread_join(id, &ret));
>         assert(ret == ret_value);
>     }
>     assert(counter == init_counter_value);
> #endif /*__cplusplus */
>     return 0;
> }
> ===================================
>
> PS3: Changes to the 'tests/Makefile' (diff file, use patch):
> ===================================
> --- ..\..\pthreads\tests\Makefile       Fri Oct 26 12:12:48 2001
> +++ Makefile    Tue Dec 18 14:16:00 2001
> @@ -41,7 +41,7 @@
>           mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass
mutex2.pass
> mutex3.pass  \
>           condvar1.pass  condvar2.pass  condvar2_1.pass  \
>           exit1.pass  create1.pass  equal1.pass  \
> -         exit2.pass  exit3.pass  \
> +         exit2.pass  exit3.pass exit4.pass \
>           join0.pass  join1.pass  join2.pass  \
>           mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass
mutex6r.pass
> \
>           count1.pass  once1.pass  tsd1.pass  \
> @@ -186,6 +186,7 @@
>  exit1.pass:
>  exit2.pass: create1.pass
>  exit3.pass: create1.pass
> +exit4.pass: create1.pass
>  eyal1.pass: tsd1.pass
>  inherit1.pass: join1.pass
>  join0.pass: create1.pass
> ===================================
>
> This message may contain privileged and/or confidential information.  If
you
> have received this e-mail in error or are not the intended recipient, you
> may not use, copy, disseminate, or distribute it; do not open any
> attachments, delete it immediately from your system and notify the sender
by
> e-mail promptly that you have done so.  Thank You.



This message may contain privileged and/or confidential information.  If
you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender
by
e-mail promptly that you have done so.  Thank You.



This message may contain privileged and/or confidential information.  If you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender by
e-mail promptly that you have done so.  Thank You.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-02-01  6:46 Alexander Terekhov
@ 2001-12-19 11:30 ` Alexander Terekhov
  0 siblings, 0 replies; 32+ messages in thread
From: Alexander Terekhov @ 2001-12-19 11:30 UTC (permalink / raw)
  To: pthreads-win32

> Due to the nature of the beast just as the responsibility lies with the
> programmer to design the program to "cleanly" (including running
destructors,
> ad nauseum) exit when exit() is called, it should also be the
responsibility of
> the programmer to design a thread to cleanly exit with pthread_exit() or
> pthread_cancel() are called.  Just as exit() should not be called in a
C++
> program if dtors are desired to run neither should pthread_exit() from a
> thread.  IMHO.

The C++ standard says:

"The function exit() has additional behavior in this
 International Standard:

 - First, objects with static storage duration are
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   destroyed and functions registered by calling
   ^^^^^^^^^
   atexit are called. Objects with static storage
   duration are destroyed in the reverse order of
   the completion of their constructor.
   (Automatic objects are not destroyed
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   as a result of calling exit().) "

but that has nothing to do with behavior
of pthread_cancel/exit wrt destruction of
automatic objects and C thread cleanup
handlers (see the last paragraph below).

The POSIX standard (non-normative Rationale volume) says:

"Thread Cancelation Cleanup Handlers
 .
 .
 .
 The alternative to providing these simple cancelation cleanup
 handlers (whose only use is for cleaning up when a thread is
 canceled) is to define a general exception package that could
 be used for handling and cleaning up after hardware traps and
 software-detected errors. This was too far removed from the
 charter of providing threads to handle asynchrony. However,
 it is an explicit goal of IEEE Std 1003.1-2001 to be compatible
 with existing exception facilities and languages having
 exceptions.

 The interaction of this facility and other procedure-based or
 language-level exception facilities is unspecified in this
 version of IEEE Std 1003.1-2001. However, it is intended that
 it be possible for an implementation to define the relationship
 between these cancelation cleanup handlers and Ada, C++, or
 other language-level exception handling facilities.

 It was suggested that the cancelation cleanup handlers should
 also be called when the process exits or calls the exec function.
 This was rejected partly due to the performance problem caused
 by having to call the cancelation cleanup handlers of every
 thread before the operation could continue. The other reason was
 that the only state expected to be cleaned up by the cancelation
 cleanup handlers would be the intraprocess state. Any handlers
 that are to clean up the interprocess state would be registered
 with atexit ( ). "

regards,
alexander.


reentrant <reentrant@yahoo.com>@sources.redhat.com on 12/19/2001 07:22:13
PM

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
cc:
Subject:  Re: pthreads VCE: problem with destructor




Due to the nature of the beast just as the responsibility lies with the
programmer to design the program to "cleanly" (including running
destructors,
ad nauseum) exit when exit() is called, it should also be the
responsibility of
the programmer to design a thread to cleanly exit with pthread_exit() or
pthread_cancel() are called.  Just as exit() should not be called in a C++
program if dtors are desired to run neither should pthread_exit() from a
thread.  IMHO.

I would imagine that exit() was chosen not to be modified to account for
running C++ destructors for about the same reasons that pthread_exit()
should
not account for running C++ destructors.  Dtors not being called in these
cases
is and should be expected behavior.

Regardless as Mr. Bossom so well has already stated: I certainly wouldn't
depend on pthread_exit() or pthread_cancel() allowing destructors to run to
be
portable though.  Since the primary purpose of this library is to enhance
portability of programs using pthreads, counting on pthread_exit() or
pthread_cancel() to work in a non-portable way seems self-defeating.

Simple sample programs included in the distribution of pthreads to
demonstrate
the technique might help.  Maybe something like:

class AppExit
{
public:
    AppExit( int status ) :
        m_status( status )
    {}
    ~AppExit( void )
    {}

    int GetStatus( void ) const
    { return m_status; }

private:
    int m_status;
};

void function( void )
{
    // blah blah blah

    if( true )
    {
        // Error.  blah blah blah failed.
        throw AppExit( 3 );
    }

    // blah blah blah succeeded,
    // continue execution as usual...
}

int main( void )
{
    try
    {
        // Call functions and what not.
        // If an abrupt exit is required
        // throw AppExit to unwind the stack
        // and exit in the catch block.
        function( );
    }
    catch( const AppExit& ae )
    {
        // App requested to exit.
        // exit() itself not used here so
        // global and other dtors will run
        // correctly.
        return ae.GetStatus( );
    }
    return 0;
}

Replace "AppExit" with something like "ThreadExit" and "main" with the name
of
the thread entry point function, account for the return value type
difference
and there's an example for cleanly exiting a thread (I'm confident the
similar
parallel can be figured out without explicitly spelling it out :).

I'm not even going to attempt to touch the complexities or nuances of
issues
related to clean cancellation in any language or on any OS :).  I'd instead
recommend against cancellation altogether and recommend using a mechanism
to
signal the thread to exit itself (like throwing an exception above or
something).  But that's another story and just an opinion.  Cancellation is
covered in plenty depth elsewhere.

While attempting to allow dtors to be run upon a pthread_exit() or
pthread_cancel() is certainly a noble goal, it's beyond the scope of the
pthread library.  It's the programmer's responsibility IMHO.

So, as I hope is obvious by this point :), I am completely in support of
the
"nasty hacks" being removed and a clean C interface version of the library
being provided only.

My two cents,
Dave


--- Ross Johnson <rpj@ise.canberra.edu.au> wrote:
> I sense a rising and ruthless desire to deal with the problem of
> the exception-based versions of the library. It would certainly
> be a lot easier if they weren't there, and there are some
> hacks in pthread.h supporting them that really are nasty.
>
> So ... what to do about them?
>
> I will firstly put John's warning in the README file
> and the README.NONPORTABLE file, and on the Web page.
>
> Secondly, there is a standard C version of the library courtesy
> of Thomas Pfaff's contributions. It uses setjmp/longjmp.
> Does this need to be built differently to work with C++
> applications (assuming they are written as John suggests they
> should be)? I can try putting it through the VCE run of the
> test suite as soon as I reinstall my corrupted Windows 98 machine.
>
> Thirdly, if possible, consider phasing out all but the VC and GC
> versions of the library (currently the only standard C versions).
> That is, phase out the VCE, VSE, and GCE versions.
>
> Does anyone wan't to jump up and shout - NO!!
>
> Ross
>


__________________________________________________
Do You Yahoo!?
Check out Yahoo! Shopping and Yahoo! Auctions for all of
your unique holiday gifts! Buy at http://shopping.yahoo.com
or bid at http://auctions.yahoo.com



^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
  2001-01-24 21:42 Alexander Terekhov
@ 2001-12-19 11:01 ` Alexander Terekhov
  0 siblings, 0 replies; 32+ messages in thread
From: Alexander Terekhov @ 2001-12-19 11:01 UTC (permalink / raw)
  To: pthreads-win32

> Alexander, it is not clear to me what you are strongly disagreeing
> with... my recommendation? (and it is not solely my recommendation,
> I can quote oodles of books recommending the same approach)

Yes.

> However, pthread_cancel is not documented as working in
> tandem with C++ stack unwinding.

I believe that it should be documented that a version
of pthreads-win32 library meant to be used in C++ programs
DOES work in tandem with C++ stack unwinding. Note that it
has nothing to do with a version of pthreads-win32 library
meant to be used in pure C programs.

> I would not recommend using it in a C++ application.

Personally, I disagree strongly with this approach.
I would ask pthread-lib vendor to provide C++ aware
pthread library, instead.

> To deal with "cancel",
> I would recommend representing a unit of work (i.e. a task)
> as an object that supports it's own ability to "cancel".
> A thread is just a means to an end... you want to do
> a unit of work. A unit of work could be executed directly,
> or within a thread, or tasked through a thread pool. The
> easiest, consistent, method of cancelling it is to cancel
> the task, not the "worker" trying to do the task.

Jobs/Tasks are OK, but they are not threads.
pthread_cancel and _exit are designed for threads.

> The only advantage that pthread_cancel has (on unix, that is)
> is that some basic C library methods that block are cancellable
> by pthread_cancel. You don't have this luxury on win32 unless you
> re-write the C runtime library with pthreads-win32.

Well, for example, how about waiting on condition
variable? That is a cancellation point that works
even with pthreads-win32. I do not want to replace
it with modified predicates which would include
"me->canceled()" flag. I do not want to know which
mutexes need to be locked and which condition variables
need to be signaled/broadcasted for a particular thread
to archive the effect meant to be provided by the
pthread_cancel.

I just want that in addition to C thread cleanup
handlers, thread cancel/exit would invoke C++
destructors and "catch(...)" handlers.

regards,
alexander.


"Bossom, John" <John.Bossom@Cognos.COM>@sources.redhat.com on 12/19/2001
03:00:58 PM

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   Alexander Terekhov/Germany/IBM@IBMDE,
      pthreads-win32@sources.redhat.com
cc:
Subject:  RE: pthreads VCE: problem with destructor



Alexander, it is not clear to me what you are strongly disagreeing
with... my recommendation? (and it is not solely my recommendation,
I can quote oodles of books recommending the same approach)

However, pthread_cancel is not documented as working in
tandem with C++ stack unwinding. I would not recommend
using it in a C++ application.

To deal with "cancel",
I would recommend representing a unit of work (i.e. a task)
as an object that supports it's own ability to "cancel".
A thread is just a means to an end... you want to do
a unit of work. A unit of work could be executed directly,
or within a thread, or tasked through a thread pool. The
easiest, consistent, method of cancelling it is to cancel
the task, not the "worker" trying to do the task.
The only advantage that pthread_cancel has (on unix, that is)
is that some basic C library methods that block are cancellable
by pthread_cancel. You don't have this luxury on win32 unless you
re-write the C runtime library with pthreads-win32.

Just my 2 cents.

Good Luck,

John.


-----Original Message-----
From: Alexander Terekhov [ mailto:TEREKHOV@de.ibm.com ]
Sent: December 19, 2001 7:41 AM
To: pthreads-win32@sources.redhat.com
Subject: Re: pthreads VCE: problem with destructor



> > Recommended approach when using C++ in conjunction with pthreads is to
> > NEVER use pthread_exit... you should have your code return to your
> > thread mainline (use exceptions if you choose) and simply "return"
> > from the thread mainline.

How about pthread_cancel? Are you saying that I should
never use it in a threaded C++ program for the same
reason(s) as pthread_exit?

Personally, I disagree strongly with this approach.

FYI:

http://groups.google.com/groups?as_umsgid=362DCB0D.230D900%40zko.dec.com
http://groups.google.com/groups?as_umsgid=kZ7h7.623%24bB1.30401%40news.cpqco

rp.net
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0004.HTM#cancel_excep_sec
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0001.HTM#index_x_53

"Several Threads Library features and most Threads Library
 identifiers are provided as C language macros. As such,
 their definitions may not be available in other languages.
 Developers working in other languages will have to provide
 their own declarations of functions and constants, and
 features such as TRY/CATCH exception handling and POSIX
 push/pop cleanup handlers may be completely unavailable
 (although it may be possible to provide similar
 functionality using native exception handling facilities).
 Note that in this context, C++ is a non-C language;
 while the C language macros may compile successfully
 under C++, TRY/CATCH and push/pop cleanup handlers
 are not supported for C++ code. C++ code should use
 object descructors and C++ exception handlers. "
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0011.HTM#excep_defs

"Exception         Definition
 ================  ===================================
 pthread_cancel_e  Thread cancelation in progress
 .
 .
 .
 pthread_exit_e    Thread exiting using pthread_exit()"

regards,
alexander.


Ross Johnson <rpj@ise.canberra.edu.au>@sources.redhat.com on 12/19/2001
12:37:59 PM

Please respond to rpj@ise.canberra.edu.au

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Bossom, John" <John.Bossom@Cognos.COM>
cc:   "'Gardian, Milan'" <Milan.Gardian@LEIBINGER.com>,
      "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
Subject:  Re: pthreads VCE: problem with destructor



I sense a rising and ruthless desire to deal with the problem of
the exception-based versions of the library. It would certainly
be a lot easier if they weren't there, and there are some
hacks in pthread.h supporting them that really are nasty.

So ... what to do about them?

I will firstly put John's warning in the README file
and the README.NONPORTABLE file, and on the Web page.

Secondly, there is a standard C version of the library courtesy
of Thomas Pfaff's contributions. It uses setjmp/longjmp.
Does this need to be built differently to work with C++
applications (assuming they are written as John suggests they
should be)? I can try putting it through the VCE run of the
test suite as soon as I reinstall my corrupted Windows 98 machine.

Thirdly, if possible, consider phasing out all but the VC and GC
versions of the library (currently the only standard C versions).
That is, phase out the VCE, VSE, and GCE versions.

Does anyone wan't to jump up and shout - NO!!

Ross

"Bossom, John" wrote:
>
> <Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)
>
> You are entering dark territory here. You are assuming that
> Operating System primitives actually cooperate with C++ primitives (i.e
> exception handling, implicit
> call of local destructors)
> This is not the case. At the time of implementation of pthread_win32
> (original version) pthread_exit on UNIX did NOT call the C++ destructors
> and perform graceful stack unwinding. pthread_exit basically did an end
run
> exit and locally called all registered pthread cleanup methods.
>
> Recommended approach when using C++ in conjunction with pthreads is to
> NEVER use pthread_exit... you should have your code return to your
> thread mainline (use exceptions if you choose) and simply "return"
> from the thread mainline.
>
> If you (Ross) implement this marrying of C++ stack-unwinding with
> pthread_exit, I suggest you
> document that it is not typical behavior and you can expect that if you
port
> your code back
> to various unix platforms that actually support pthreads natively, you
> will encounter exactly the same problem.
>
> -----Original Message-----
> From: Gardian, Milan [ mailto:Milan.Gardian@LEIBINGER.com ]
> Sent: December 18, 2001 9:17 AM
> To: Pthreads-Win32@Sources.Redhat.Com
> Cc: Ross Johnson (E-mail)
> Subject: pthreads VCE: problem with destructor
>
> Hi,
>
> I came across a problem with pthreads VCE: destructors for objects in
local
> scope (automatic variables on stack) of the thread-function are not
called
> when using 'pthread_exit' to exit the thread (or when using any function
> that eventually throws a C++ exception (because of VCE build) using
> ptw32_throw internal function).
>
> To illustrate this point I created a new test case, 'exit4.c'. It uses a
C++
> guard object to increment a shared reference count in constructor and
> decrement it in destructor. This object is then created on stack in both
the
> main thread (before creating the new thread) and in the thread-function
> (i.e. reference count is increased by 2).
>
> If we finish the thread-function by returning from it (falling off the
end),
> destructor for both objects is called as expected (first the
thread-function
> local object and then the main thread local object). This case is
> illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line
11
> -> the test case passes.
>
> On the other hand if we finish the thread-function by using
'pthread_exit'
> instead of falling off the end, the destructor for the thread-function
local
> object is NOT called (although the destructor for main thread local
object
> is called). This case is illustrated by compiling with the macro
> USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.
>
> C++ resource idiom (acquire in constructor, release in destructor) is
used
> throughout our threaded program. The described behaviour of pthreads is
> introducing possibility of a resource leak and potential deadlock. Does
> anybody have any ideas what is happening and how to resolve the problem?
>
> Thank you very much for your replies and help,
>
> Cheers,
>
>         Milan
>
> PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
> June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
> 17-DEC-2001 by Ross)
>
> PS1: Note that the reference counting need not be protected by a mutex as
it
> will never be accessed simultaneously by both threads due to
synchronization
> using pthread_join.
>
> PS2: The exit4.c file
> ===================================
> /*
>  * Test for pthread_exit().
>  *
>  * Depends on API functions: pthread_create().
>  */
>
> #include "test.h"
>
> #ifdef __cplusplus
>
> #define USE_PTHREAD_EXIT
> static const int init_counter_value = 3;
> static void *ret_value = reinterpret_cast<void *>(1);
> static int counter = init_counter_value;
>
> class Guard
> {
>     const char * const _str;
>     int &_ref;
>     Guard &operator=(const Guard&);
>     Guard(const Guard&);
> public:
>     Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
>         printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
>     };
>     ~Guard() {
>         printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
>     };
> };
>
> void *
> func(void * arg)
> {
>     Guard g("func", counter);
> #ifdef USE_PTHREAD_EXIT
>     pthread_exit(arg);
>     assert(0); //Never reached with pthread_exit
> #endif //USE_PTHREAD_EXIT
>     return ret_value;
> }
>
> #endif /*__cplusplus */
>
> int main(int, char **)
> {
> #ifndef __cplusplus
>     printf("Test requires C++. Skipped.\n");
> #else
>     {
>         void *ret = 0;
>         Guard g("main", counter);
>         pthread_t id;
>         assert(0 == pthread_create(&id, 0, func, ret_value));
>         assert(0 == pthread_join(id, &ret));
>         assert(ret == ret_value);
>     }
>     assert(counter == init_counter_value);
> #endif /*__cplusplus */
>     return 0;
> }
> ===================================
>
> PS3: Changes to the 'tests/Makefile' (diff file, use patch):
> ===================================
> --- ..\..\pthreads\tests\Makefile       Fri Oct 26 12:12:48 2001
> +++ Makefile    Tue Dec 18 14:16:00 2001
> @@ -41,7 +41,7 @@
>           mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass
mutex2.pass
> mutex3.pass  \
>           condvar1.pass  condvar2.pass  condvar2_1.pass  \
>           exit1.pass  create1.pass  equal1.pass  \
> -         exit2.pass  exit3.pass  \
> +         exit2.pass  exit3.pass exit4.pass \
>           join0.pass  join1.pass  join2.pass  \
>           mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass
mutex6r.pass
> \
>           count1.pass  once1.pass  tsd1.pass  \
> @@ -186,6 +186,7 @@
>  exit1.pass:
>  exit2.pass: create1.pass
>  exit3.pass: create1.pass
> +exit4.pass: create1.pass
>  eyal1.pass: tsd1.pass
>  inherit1.pass: join1.pass
>  join0.pass: create1.pass
> ===================================
>
> This message may contain privileged and/or confidential information.  If
you
> have received this e-mail in error or are not the intended recipient, you
> may not use, copy, disseminate, or distribute it; do not open any
> attachments, delete it immediately from your system and notify the sender
by
> e-mail promptly that you have done so.  Thank You.



This message may contain privileged and/or confidential information.  If
you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender
by
e-mail promptly that you have done so.  Thank You.



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-01-24 14:02   ` reentrant
  2001-03-10  6:41     ` Thomas Pfaff
@ 2001-12-19 10:22     ` reentrant
  1 sibling, 0 replies; 32+ messages in thread
From: reentrant @ 2001-12-19 10:22 UTC (permalink / raw)
  To: Pthreads-Win32@Sources.Redhat.Com

Due to the nature of the beast just as the responsibility lies with the
programmer to design the program to "cleanly" (including running destructors,
ad nauseum) exit when exit() is called, it should also be the responsibility of
the programmer to design a thread to cleanly exit with pthread_exit() or
pthread_cancel() are called.  Just as exit() should not be called in a C++
program if dtors are desired to run neither should pthread_exit() from a
thread.  IMHO.

I would imagine that exit() was chosen not to be modified to account for
running C++ destructors for about the same reasons that pthread_exit() should
not account for running C++ destructors.  Dtors not being called in these cases
is and should be expected behavior.

Regardless as Mr. Bossom so well has already stated: I certainly wouldn't
depend on pthread_exit() or pthread_cancel() allowing destructors to run to be
portable though.  Since the primary purpose of this library is to enhance
portability of programs using pthreads, counting on pthread_exit() or
pthread_cancel() to work in a non-portable way seems self-defeating.

Simple sample programs included in the distribution of pthreads to demonstrate
the technique might help.  Maybe something like:

class AppExit
{
public:
    AppExit( int status ) :
        m_status( status )
    {}
    ~AppExit( void )
    {}

    int GetStatus( void ) const
    { return m_status; }

private:
    int m_status;
};

void function( void )
{
    // blah blah blah

    if( true )
    {
        // Error.  blah blah blah failed.
        throw AppExit( 3 );
    }

    // blah blah blah succeeded, 
    // continue execution as usual...
}

int main( void )
{
    try
    {
        // Call functions and what not.
        // If an abrupt exit is required
        // throw AppExit to unwind the stack
        // and exit in the catch block.
        function( );
    }
    catch( const AppExit& ae )
    {
        // App requested to exit.
        // exit() itself not used here so
        // global and other dtors will run
        // correctly.
        return ae.GetStatus( );
    }
    return 0;
}

Replace "AppExit" with something like "ThreadExit" and "main" with the name of
the thread entry point function, account for the return value type difference
and there's an example for cleanly exiting a thread (I'm confident the similar
parallel can be figured out without explicitly spelling it out :).

I'm not even going to attempt to touch the complexities or nuances of issues
related to clean cancellation in any language or on any OS :).  I'd instead
recommend against cancellation altogether and recommend using a mechanism to
signal the thread to exit itself (like throwing an exception above or
something).  But that's another story and just an opinion.  Cancellation is
covered in plenty depth elsewhere.

While attempting to allow dtors to be run upon a pthread_exit() or
pthread_cancel() is certainly a noble goal, it's beyond the scope of the
pthread library.  It's the programmer's responsibility IMHO.

So, as I hope is obvious by this point :), I am completely in support of the
"nasty hacks" being removed and a clean C interface version of the library
being provided only.

My two cents,
Dave


--- Ross Johnson <rpj@ise.canberra.edu.au> wrote:
> I sense a rising and ruthless desire to deal with the problem of
> the exception-based versions of the library. It would certainly
> be a lot easier if they weren't there, and there are some
> hacks in pthread.h supporting them that really are nasty.
> 
> So ... what to do about them?
> 
> I will firstly put John's warning in the README file
> and the README.NONPORTABLE file, and on the Web page.
> 
> Secondly, there is a standard C version of the library courtesy
> of Thomas Pfaff's contributions. It uses setjmp/longjmp.
> Does this need to be built differently to work with C++
> applications (assuming they are written as John suggests they
> should be)? I can try putting it through the VCE run of the
> test suite as soon as I reinstall my corrupted Windows 98 machine.
> 
> Thirdly, if possible, consider phasing out all but the VC and GC
> versions of the library (currently the only standard C versions).
> That is, phase out the VCE, VSE, and GCE versions.
> 
> Does anyone wan't to jump up and shout - NO!!
> 
> Ross
> 


__________________________________________________
Do You Yahoo!?
Check out Yahoo! Shopping and Yahoo! Auctions for all of
your unique holiday gifts! Buy at http://shopping.yahoo.com
or bid at http://auctions.yahoo.com

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
  2001-01-16 16:48 Bossom, John
@ 2001-12-19  6:02 ` Bossom, John
  0 siblings, 0 replies; 32+ messages in thread
From: Bossom, John @ 2001-12-19  6:02 UTC (permalink / raw)
  To: 'Alexander Terekhov', pthreads-win32

Alexander, it is not clear to me what you are strongly disagreeing
with... my recommendation? (and it is not solely my recommendation,
I can quote oodles of books recommending the same approach)

However, pthread_cancel is not documented as working in
tandem with C++ stack unwinding. I would not recommend
using it in a C++ application.

To deal with "cancel",
I would recommend representing a unit of work (i.e. a task)
as an object that supports it's own ability to "cancel".
A thread is just a means to an end... you want to do
a unit of work. A unit of work could be executed directly,
or within a thread, or tasked through a thread pool. The
easiest, consistent, method of cancelling it is to cancel
the task, not the "worker" trying to do the task.
The only advantage that pthread_cancel has (on unix, that is)
is that some basic C library methods that block are cancellable
by pthread_cancel. You don't have this luxury on win32 unless you
re-write the C runtime library with pthreads-win32.

Just my 2 cents.

Good Luck,

John.


-----Original Message-----
From: Alexander Terekhov [ mailto:TEREKHOV@de.ibm.com ]
Sent: December 19, 2001 7:41 AM
To: pthreads-win32@sources.redhat.com
Subject: Re: pthreads VCE: problem with destructor



> > Recommended approach when using C++ in conjunction with pthreads is to
> > NEVER use pthread_exit... you should have your code return to your
> > thread mainline (use exceptions if you choose) and simply "return"
> > from the thread mainline.

How about pthread_cancel? Are you saying that I should
never use it in a threaded C++ program for the same
reason(s) as pthread_exit?

Personally, I disagree strongly with this approach.

FYI:

http://groups.google.com/groups?as_umsgid=362DCB0D.230D900%40zko.dec.com
http://groups.google.com/groups?as_umsgid=kZ7h7.623%24bB1.30401%40news.cpqco
rp.net
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB
TE/DOCU0004.HTM#cancel_excep_sec
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB
TE/DOCU0001.HTM#index_x_53

"Several Threads Library features and most Threads Library
 identifiers are provided as C language macros. As such,
 their definitions may not be available in other languages.
 Developers working in other languages will have to provide
 their own declarations of functions and constants, and
 features such as TRY/CATCH exception handling and POSIX
 push/pop cleanup handlers may be completely unavailable
 (although it may be possible to provide similar
 functionality using native exception handling facilities).
 Note that in this context, C++ is a non-C language;
 while the C language macros may compile successfully
 under C++, TRY/CATCH and push/pop cleanup handlers
 are not supported for C++ code. C++ code should use
 object descructors and C++ exception handlers. "
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB
TE/DOCU0011.HTM#excep_defs

"Exception         Definition
 ================  ===================================
 pthread_cancel_e  Thread cancelation in progress
 .
 .
 .
 pthread_exit_e    Thread exiting using pthread_exit()"

regards,
alexander.


Ross Johnson <rpj@ise.canberra.edu.au>@sources.redhat.com on 12/19/2001
12:37:59 PM

Please respond to rpj@ise.canberra.edu.au

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Bossom, John" <John.Bossom@Cognos.COM>
cc:   "'Gardian, Milan'" <Milan.Gardian@LEIBINGER.com>,
      "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
Subject:  Re: pthreads VCE: problem with destructor



I sense a rising and ruthless desire to deal with the problem of
the exception-based versions of the library. It would certainly
be a lot easier if they weren't there, and there are some
hacks in pthread.h supporting them that really are nasty.

So ... what to do about them?

I will firstly put John's warning in the README file
and the README.NONPORTABLE file, and on the Web page.

Secondly, there is a standard C version of the library courtesy
of Thomas Pfaff's contributions. It uses setjmp/longjmp.
Does this need to be built differently to work with C++
applications (assuming they are written as John suggests they
should be)? I can try putting it through the VCE run of the
test suite as soon as I reinstall my corrupted Windows 98 machine.

Thirdly, if possible, consider phasing out all but the VC and GC
versions of the library (currently the only standard C versions).
That is, phase out the VCE, VSE, and GCE versions.

Does anyone wan't to jump up and shout - NO!!

Ross

"Bossom, John" wrote:
>
> <Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)
>
> You are entering dark territory here. You are assuming that
> Operating System primitives actually cooperate with C++ primitives (i.e
> exception handling, implicit
> call of local destructors)
> This is not the case. At the time of implementation of pthread_win32
> (original version) pthread_exit on UNIX did NOT call the C++ destructors
> and perform graceful stack unwinding. pthread_exit basically did an end
run
> exit and locally called all registered pthread cleanup methods.
>
> Recommended approach when using C++ in conjunction with pthreads is to
> NEVER use pthread_exit... you should have your code return to your
> thread mainline (use exceptions if you choose) and simply "return"
> from the thread mainline.
>
> If you (Ross) implement this marrying of C++ stack-unwinding with
> pthread_exit, I suggest you
> document that it is not typical behavior and you can expect that if you
port
> your code back
> to various unix platforms that actually support pthreads natively, you
> will encounter exactly the same problem.
>
> -----Original Message-----
> From: Gardian, Milan [ mailto:Milan.Gardian@LEIBINGER.com ]
> Sent: December 18, 2001 9:17 AM
> To: Pthreads-Win32@Sources.Redhat.Com
> Cc: Ross Johnson (E-mail)
> Subject: pthreads VCE: problem with destructor
>
> Hi,
>
> I came across a problem with pthreads VCE: destructors for objects in
local
> scope (automatic variables on stack) of the thread-function are not
called
> when using 'pthread_exit' to exit the thread (or when using any function
> that eventually throws a C++ exception (because of VCE build) using
> ptw32_throw internal function).
>
> To illustrate this point I created a new test case, 'exit4.c'. It uses a
C++
> guard object to increment a shared reference count in constructor and
> decrement it in destructor. This object is then created on stack in both
the
> main thread (before creating the new thread) and in the thread-function
> (i.e. reference count is increased by 2).
>
> If we finish the thread-function by returning from it (falling off the
end),
> destructor for both objects is called as expected (first the
thread-function
> local object and then the main thread local object). This case is
> illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line
11
> -> the test case passes.
>
> On the other hand if we finish the thread-function by using
'pthread_exit'
> instead of falling off the end, the destructor for the thread-function
local
> object is NOT called (although the destructor for main thread local
object
> is called). This case is illustrated by compiling with the macro
> USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.
>
> C++ resource idiom (acquire in constructor, release in destructor) is
used
> throughout our threaded program. The described behaviour of pthreads is
> introducing possibility of a resource leak and potential deadlock. Does
> anybody have any ideas what is happening and how to resolve the problem?
>
> Thank you very much for your replies and help,
>
> Cheers,
>
>         Milan
>
> PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
> June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
> 17-DEC-2001 by Ross)
>
> PS1: Note that the reference counting need not be protected by a mutex as
it
> will never be accessed simultaneously by both threads due to
synchronization
> using pthread_join.
>
> PS2: The exit4.c file
> ===================================
> /*
>  * Test for pthread_exit().
>  *
>  * Depends on API functions: pthread_create().
>  */
>
> #include "test.h"
>
> #ifdef __cplusplus
>
> #define USE_PTHREAD_EXIT
> static const int init_counter_value = 3;
> static void *ret_value = reinterpret_cast<void *>(1);
> static int counter = init_counter_value;
>
> class Guard
> {
>     const char * const _str;
>     int &_ref;
>     Guard &operator=(const Guard&);
>     Guard(const Guard&);
> public:
>     Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
>         printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
>     };
>     ~Guard() {
>         printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
>     };
> };
>
> void *
> func(void * arg)
> {
>     Guard g("func", counter);
> #ifdef USE_PTHREAD_EXIT
>     pthread_exit(arg);
>     assert(0); //Never reached with pthread_exit
> #endif //USE_PTHREAD_EXIT
>     return ret_value;
> }
>
> #endif /*__cplusplus */
>
> int main(int, char **)
> {
> #ifndef __cplusplus
>     printf("Test requires C++. Skipped.\n");
> #else
>     {
>         void *ret = 0;
>         Guard g("main", counter);
>         pthread_t id;
>         assert(0 == pthread_create(&id, 0, func, ret_value));
>         assert(0 == pthread_join(id, &ret));
>         assert(ret == ret_value);
>     }
>     assert(counter == init_counter_value);
> #endif /*__cplusplus */
>     return 0;
> }
> ===================================
>
> PS3: Changes to the 'tests/Makefile' (diff file, use patch):
> ===================================
> --- ..\..\pthreads\tests\Makefile       Fri Oct 26 12:12:48 2001
> +++ Makefile    Tue Dec 18 14:16:00 2001
> @@ -41,7 +41,7 @@
>           mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass
mutex2.pass
> mutex3.pass  \
>           condvar1.pass  condvar2.pass  condvar2_1.pass  \
>           exit1.pass  create1.pass  equal1.pass  \
> -         exit2.pass  exit3.pass  \
> +         exit2.pass  exit3.pass exit4.pass \
>           join0.pass  join1.pass  join2.pass  \
>           mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass
mutex6r.pass
> \
>           count1.pass  once1.pass  tsd1.pass  \
> @@ -186,6 +186,7 @@
>  exit1.pass:
>  exit2.pass: create1.pass
>  exit3.pass: create1.pass
> +exit4.pass: create1.pass
>  eyal1.pass: tsd1.pass
>  inherit1.pass: join1.pass
>  join0.pass: create1.pass
> ===================================
>
> This message may contain privileged and/or confidential information.  If
you
> have received this e-mail in error or are not the intended recipient, you
> may not use, copy, disseminate, or distribute it; do not open any
> attachments, delete it immediately from your system and notify the sender
by
> e-mail promptly that you have done so.  Thank You.



This message may contain privileged and/or confidential information.  If you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender by
e-mail promptly that you have done so.  Thank You.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-01-16  7:38 Alexander Terekhov
@ 2001-12-19  4:40 ` Alexander Terekhov
  0 siblings, 0 replies; 32+ messages in thread
From: Alexander Terekhov @ 2001-12-19  4:40 UTC (permalink / raw)
  To: pthreads-win32

> > Recommended approach when using C++ in conjunction with pthreads is to
> > NEVER use pthread_exit... you should have your code return to your
> > thread mainline (use exceptions if you choose) and simply "return"
> > from the thread mainline.

How about pthread_cancel? Are you saying that I should
never use it in a threaded C++ program for the same
reason(s) as pthread_exit?

Personally, I disagree strongly with this approach.

FYI:

http://groups.google.com/groups?as_umsgid=362DCB0D.230D900%40zko.dec.com
http://groups.google.com/groups?as_umsgid=kZ7h7.623%24bB1.30401%40news.cpqcorp.net
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RBTE/DOCU0004.HTM#cancel_excep_sec
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RBTE/DOCU0001.HTM#index_x_53

"Several Threads Library features and most Threads Library
 identifiers are provided as C language macros. As such,
 their definitions may not be available in other languages.
 Developers working in other languages will have to provide
 their own declarations of functions and constants, and
 features such as TRY/CATCH exception handling and POSIX
 push/pop cleanup handlers may be completely unavailable
 (although it may be possible to provide similar
 functionality using native exception handling facilities).
 Note that in this context, C++ is a non-C language;
 while the C language macros may compile successfully
 under C++, TRY/CATCH and push/pop cleanup handlers
 are not supported for C++ code. C++ code should use
 object descructors and C++ exception handlers. "
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RBTE/DOCU0011.HTM#excep_defs

"Exception         Definition
 ================  ===================================
 pthread_cancel_e  Thread cancelation in progress
 .
 .
 .
 pthread_exit_e    Thread exiting using pthread_exit()"

regards,
alexander.


Ross Johnson <rpj@ise.canberra.edu.au>@sources.redhat.com on 12/19/2001
12:37:59 PM

Please respond to rpj@ise.canberra.edu.au

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Bossom, John" <John.Bossom@Cognos.COM>
cc:   "'Gardian, Milan'" <Milan.Gardian@LEIBINGER.com>,
      "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
Subject:  Re: pthreads VCE: problem with destructor



I sense a rising and ruthless desire to deal with the problem of
the exception-based versions of the library. It would certainly
be a lot easier if they weren't there, and there are some
hacks in pthread.h supporting them that really are nasty.

So ... what to do about them?

I will firstly put John's warning in the README file
and the README.NONPORTABLE file, and on the Web page.

Secondly, there is a standard C version of the library courtesy
of Thomas Pfaff's contributions. It uses setjmp/longjmp.
Does this need to be built differently to work with C++
applications (assuming they are written as John suggests they
should be)? I can try putting it through the VCE run of the
test suite as soon as I reinstall my corrupted Windows 98 machine.

Thirdly, if possible, consider phasing out all but the VC and GC
versions of the library (currently the only standard C versions).
That is, phase out the VCE, VSE, and GCE versions.

Does anyone wan't to jump up and shout - NO!!

Ross

"Bossom, John" wrote:
>
> <Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)
>
> You are entering dark territory here. You are assuming that
> Operating System primitives actually cooperate with C++ primitives (i.e
> exception handling, implicit
> call of local destructors)
> This is not the case. At the time of implementation of pthread_win32
> (original version) pthread_exit on UNIX did NOT call the C++ destructors
> and perform graceful stack unwinding. pthread_exit basically did an end
run
> exit and locally called all registered pthread cleanup methods.
>
> Recommended approach when using C++ in conjunction with pthreads is to
> NEVER use pthread_exit... you should have your code return to your
> thread mainline (use exceptions if you choose) and simply "return"
> from the thread mainline.
>
> If you (Ross) implement this marrying of C++ stack-unwinding with
> pthread_exit, I suggest you
> document that it is not typical behavior and you can expect that if you
port
> your code back
> to various unix platforms that actually support pthreads natively, you
> will encounter exactly the same problem.
>
> -----Original Message-----
> From: Gardian, Milan [ mailto:Milan.Gardian@LEIBINGER.com ]
> Sent: December 18, 2001 9:17 AM
> To: Pthreads-Win32@Sources.Redhat.Com
> Cc: Ross Johnson (E-mail)
> Subject: pthreads VCE: problem with destructor
>
> Hi,
>
> I came across a problem with pthreads VCE: destructors for objects in
local
> scope (automatic variables on stack) of the thread-function are not
called
> when using 'pthread_exit' to exit the thread (or when using any function
> that eventually throws a C++ exception (because of VCE build) using
> ptw32_throw internal function).
>
> To illustrate this point I created a new test case, 'exit4.c'. It uses a
C++
> guard object to increment a shared reference count in constructor and
> decrement it in destructor. This object is then created on stack in both
the
> main thread (before creating the new thread) and in the thread-function
> (i.e. reference count is increased by 2).
>
> If we finish the thread-function by returning from it (falling off the
end),
> destructor for both objects is called as expected (first the
thread-function
> local object and then the main thread local object). This case is
> illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line
11
> -> the test case passes.
>
> On the other hand if we finish the thread-function by using
'pthread_exit'
> instead of falling off the end, the destructor for the thread-function
local
> object is NOT called (although the destructor for main thread local
object
> is called). This case is illustrated by compiling with the macro
> USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.
>
> C++ resource idiom (acquire in constructor, release in destructor) is
used
> throughout our threaded program. The described behaviour of pthreads is
> introducing possibility of a resource leak and potential deadlock. Does
> anybody have any ideas what is happening and how to resolve the problem?
>
> Thank you very much for your replies and help,
>
> Cheers,
>
>         Milan
>
> PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
> June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
> 17-DEC-2001 by Ross)
>
> PS1: Note that the reference counting need not be protected by a mutex as
it
> will never be accessed simultaneously by both threads due to
synchronization
> using pthread_join.
>
> PS2: The exit4.c file
> ===================================
> /*
>  * Test for pthread_exit().
>  *
>  * Depends on API functions: pthread_create().
>  */
>
> #include "test.h"
>
> #ifdef __cplusplus
>
> #define USE_PTHREAD_EXIT
> static const int init_counter_value = 3;
> static void *ret_value = reinterpret_cast<void *>(1);
> static int counter = init_counter_value;
>
> class Guard
> {
>     const char * const _str;
>     int &_ref;
>     Guard &operator=(const Guard&);
>     Guard(const Guard&);
> public:
>     Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
>         printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
>     };
>     ~Guard() {
>         printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
>     };
> };
>
> void *
> func(void * arg)
> {
>     Guard g("func", counter);
> #ifdef USE_PTHREAD_EXIT
>     pthread_exit(arg);
>     assert(0); //Never reached with pthread_exit
> #endif //USE_PTHREAD_EXIT
>     return ret_value;
> }
>
> #endif /*__cplusplus */
>
> int main(int, char **)
> {
> #ifndef __cplusplus
>     printf("Test requires C++. Skipped.\n");
> #else
>     {
>         void *ret = 0;
>         Guard g("main", counter);
>         pthread_t id;
>         assert(0 == pthread_create(&id, 0, func, ret_value));
>         assert(0 == pthread_join(id, &ret));
>         assert(ret == ret_value);
>     }
>     assert(counter == init_counter_value);
> #endif /*__cplusplus */
>     return 0;
> }
> ===================================
>
> PS3: Changes to the 'tests/Makefile' (diff file, use patch):
> ===================================
> --- ..\..\pthreads\tests\Makefile       Fri Oct 26 12:12:48 2001
> +++ Makefile    Tue Dec 18 14:16:00 2001
> @@ -41,7 +41,7 @@
>           mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass
mutex2.pass
> mutex3.pass  \
>           condvar1.pass  condvar2.pass  condvar2_1.pass  \
>           exit1.pass  create1.pass  equal1.pass  \
> -         exit2.pass  exit3.pass  \
> +         exit2.pass  exit3.pass exit4.pass \
>           join0.pass  join1.pass  join2.pass  \
>           mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass
mutex6r.pass
> \
>           count1.pass  once1.pass  tsd1.pass  \
> @@ -186,6 +186,7 @@
>  exit1.pass:
>  exit2.pass: create1.pass
>  exit3.pass: create1.pass
> +exit4.pass: create1.pass
>  eyal1.pass: tsd1.pass
>  inherit1.pass: join1.pass
>  join0.pass: create1.pass
> ===================================
>
> This message may contain privileged and/or confidential information.  If
you
> have received this e-mail in error or are not the intended recipient, you
> may not use, copy, disseminate, or distribute it; do not open any
> attachments, delete it immediately from your system and notify the sender
by
> e-mail promptly that you have done so.  Thank You.



^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
  2001-01-16  1:18 Gardian, Milan
@ 2001-12-19  4:05 ` Gardian, Milan
  0 siblings, 0 replies; 32+ messages in thread
From: Gardian, Milan @ 2001-12-19  4:05 UTC (permalink / raw)
  To: Mike Kinghan, Pthreads-Win32@Sources.Redhat.Com
  Cc: Ross Johnson (E-mail), John Bossom (E-mail)

Hi Mike,

> Yeah, I have encountered similar problems. I presume
> you are using MS VC++ 6.0 and that these disappearing
> destructors affect your release build but not your
> debug build?

Just wanted to let you know that the problem occurs in debug build as well.
I tried two things:

1. the pthreads distribution, compiled using the command-line VC++
compiler/linker (that contains the full debug info, no optimisations) ->
added a test 'exit4.c' that fails, as described in my previous mail

2. pthreads library compiled from VC++ GUI environment (pthreads.dsp + a
test project). This was a bit more complex than the 'exit4.c' test but also
failed - in both debug (no optimisations) and release builds

I eventually tracked the problem down to

  extern "C"

versus

  extern

function declaration+definition. If the exception is thrown from a function
that was exported as extern "C" from the DLL, destructor is not called
(stack rollback is not performed). On the other hand if the exception is
thrown from a function exported as extern (C++ name mangling and co.), there
is no problem at all (full stack rollback -> destructor call).

Anyway I liked the contribution from John Bossom and will support the
removal of VCE version of pthreads from the library as suggested by Ross
Johnson. I think the C++ stuff introduces more problems than it fixes...

Cheers,

	Milan

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-01-15  7:40 ` Ross Johnson
  2001-01-24 14:02   ` reentrant
@ 2001-12-19  3:38   ` Ross Johnson
  1 sibling, 0 replies; 32+ messages in thread
From: Ross Johnson @ 2001-12-19  3:38 UTC (permalink / raw)
  To: Bossom, John; +Cc: 'Gardian, Milan', Pthreads-Win32@Sources.Redhat.Com

I sense a rising and ruthless desire to deal with the problem of
the exception-based versions of the library. It would certainly
be a lot easier if they weren't there, and there are some
hacks in pthread.h supporting them that really are nasty.

So ... what to do about them?

I will firstly put John's warning in the README file
and the README.NONPORTABLE file, and on the Web page.

Secondly, there is a standard C version of the library courtesy
of Thomas Pfaff's contributions. It uses setjmp/longjmp.
Does this need to be built differently to work with C++
applications (assuming they are written as John suggests they
should be)? I can try putting it through the VCE run of the
test suite as soon as I reinstall my corrupted Windows 98 machine.

Thirdly, if possible, consider phasing out all but the VC and GC
versions of the library (currently the only standard C versions).
That is, phase out the VCE, VSE, and GCE versions.

Does anyone wan't to jump up and shout - NO!!

Ross

"Bossom, John" wrote:
> 
> <Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)
> 
> You are entering dark territory here. You are assuming that
> Operating System primitives actually cooperate with C++ primitives (i.e
> exception handling, implicit
> call of local destructors)
> This is not the case. At the time of implementation of pthread_win32
> (original version) pthread_exit on UNIX did NOT call the C++ destructors
> and perform graceful stack unwinding. pthread_exit basically did an end run
> exit and locally called all registered pthread cleanup methods.
> 
> Recommended approach when using C++ in conjunction with pthreads is to
> NEVER use pthread_exit... you should have your code return to your
> thread mainline (use exceptions if you choose) and simply "return"
> from the thread mainline.
> 
> If you (Ross) implement this marrying of C++ stack-unwinding with
> pthread_exit, I suggest you
> document that it is not typical behavior and you can expect that if you port
> your code back
> to various unix platforms that actually support pthreads natively, you
> will encounter exactly the same problem.
> 
> -----Original Message-----
> From: Gardian, Milan [ mailto:Milan.Gardian@LEIBINGER.com ]
> Sent: December 18, 2001 9:17 AM
> To: Pthreads-Win32@Sources.Redhat.Com
> Cc: Ross Johnson (E-mail)
> Subject: pthreads VCE: problem with destructor
> 
> Hi,
> 
> I came across a problem with pthreads VCE: destructors for objects in local
> scope (automatic variables on stack) of the thread-function are not called
> when using 'pthread_exit' to exit the thread (or when using any function
> that eventually throws a C++ exception (because of VCE build) using
> ptw32_throw internal function).
> 
> To illustrate this point I created a new test case, 'exit4.c'. It uses a C++
> guard object to increment a shared reference count in constructor and
> decrement it in destructor. This object is then created on stack in both the
> main thread (before creating the new thread) and in the thread-function
> (i.e. reference count is increased by 2).
> 
> If we finish the thread-function by returning from it (falling off the end),
> destructor for both objects is called as expected (first the thread-function
> local object and then the main thread local object). This case is
> illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line 11
> -> the test case passes.
> 
> On the other hand if we finish the thread-function by using 'pthread_exit'
> instead of falling off the end, the destructor for the thread-function local
> object is NOT called (although the destructor for main thread local object
> is called). This case is illustrated by compiling with the macro
> USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.
> 
> C++ resource idiom (acquire in constructor, release in destructor) is used
> throughout our threaded program. The described behaviour of pthreads is
> introducing possibility of a resource leak and potential deadlock. Does
> anybody have any ideas what is happening and how to resolve the problem?
> 
> Thank you very much for your replies and help,
> 
> Cheers,
> 
>         Milan
> 
> PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
> June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
> 17-DEC-2001 by Ross)
> 
> PS1: Note that the reference counting need not be protected by a mutex as it
> will never be accessed simultaneously by both threads due to synchronization
> using pthread_join.
> 
> PS2: The exit4.c file
> ===================================
> /*
>  * Test for pthread_exit().
>  *
>  * Depends on API functions: pthread_create().
>  */
> 
> #include "test.h"
> 
> #ifdef __cplusplus
> 
> #define USE_PTHREAD_EXIT
> static const int init_counter_value = 3;
> static void *ret_value = reinterpret_cast<void *>(1);
> static int counter = init_counter_value;
> 
> class Guard
> {
>     const char * const _str;
>     int &_ref;
>     Guard &operator=(const Guard&);
>     Guard(const Guard&);
> public:
>     Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
>         printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
>     };
>     ~Guard() {
>         printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
>     };
> };
> 
> void *
> func(void * arg)
> {
>     Guard g("func", counter);
> #ifdef USE_PTHREAD_EXIT
>     pthread_exit(arg);
>     assert(0); //Never reached with pthread_exit
> #endif //USE_PTHREAD_EXIT
>     return ret_value;
> }
> 
> #endif /*__cplusplus */
> 
> int main(int, char **)
> {
> #ifndef __cplusplus
>     printf("Test requires C++. Skipped.\n");
> #else
>     {
>         void *ret = 0;
>         Guard g("main", counter);
>         pthread_t id;
>         assert(0 == pthread_create(&id, 0, func, ret_value));
>         assert(0 == pthread_join(id, &ret));
>         assert(ret == ret_value);
>     }
>     assert(counter == init_counter_value);
> #endif /*__cplusplus */
>     return 0;
> }
> ===================================
> 
> PS3: Changes to the 'tests/Makefile' (diff file, use patch):
> ===================================
> --- ..\..\pthreads\tests\Makefile       Fri Oct 26 12:12:48 2001
> +++ Makefile    Tue Dec 18 14:16:00 2001
> @@ -41,7 +41,7 @@
>           mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass  mutex2.pass
> mutex3.pass  \
>           condvar1.pass  condvar2.pass  condvar2_1.pass  \
>           exit1.pass  create1.pass  equal1.pass  \
> -         exit2.pass  exit3.pass  \
> +         exit2.pass  exit3.pass exit4.pass \
>           join0.pass  join1.pass  join2.pass  \
>           mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass  mutex6r.pass
> \
>           count1.pass  once1.pass  tsd1.pass  \
> @@ -186,6 +186,7 @@
>  exit1.pass:
>  exit2.pass: create1.pass
>  exit3.pass: create1.pass
> +exit4.pass: create1.pass
>  eyal1.pass: tsd1.pass
>  inherit1.pass: join1.pass
>  join0.pass: create1.pass
> ===================================
> 
> This message may contain privileged and/or confidential information.  If you
> have received this e-mail in error or are not the intended recipient, you
> may not use, copy, disseminate, or distribute it; do not open any
> attachments, delete it immediately from your system and notify the sender by
> e-mail promptly that you have done so.  Thank You.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
  2001-01-11  7:04 Bossom, John
  2001-01-15  7:40 ` Ross Johnson
@ 2001-12-18 12:22 ` Bossom, John
  1 sibling, 0 replies; 32+ messages in thread
From: Bossom, John @ 2001-12-18 12:22 UTC (permalink / raw)
  To: 'Gardian, Milan', Pthreads-Win32@Sources.Redhat.Com
  Cc: Ross Johnson (E-mail)

<Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)

You are entering dark territory here. You are assuming that
Operating System primitives actually cooperate with C++ primitives (i.e
exception handling, implicit
call of local destructors)
This is not the case. At the time of implementation of pthread_win32
(original version) pthread_exit on UNIX did NOT call the C++ destructors
and perform graceful stack unwinding. pthread_exit basically did an end run
exit and locally called all registered pthread cleanup methods.

Recommended approach when using C++ in conjunction with pthreads is to
NEVER use pthread_exit... you should have your code return to your
thread mainline (use exceptions if you choose) and simply "return"
from the thread mainline.

If you (Ross) implement this marrying of C++ stack-unwinding with
pthread_exit, I suggest you
document that it is not typical behavior and you can expect that if you port
your code back
to various unix platforms that actually support pthreads natively, you
will encounter exactly the same problem.


-----Original Message-----
From: Gardian, Milan [ mailto:Milan.Gardian@LEIBINGER.com ]
Sent: December 18, 2001 9:17 AM
To: Pthreads-Win32@Sources.Redhat.Com
Cc: Ross Johnson (E-mail)
Subject: pthreads VCE: problem with destructor


Hi,

I came across a problem with pthreads VCE: destructors for objects in local
scope (automatic variables on stack) of the thread-function are not called
when using 'pthread_exit' to exit the thread (or when using any function
that eventually throws a C++ exception (because of VCE build) using
ptw32_throw internal function).

To illustrate this point I created a new test case, 'exit4.c'. It uses a C++
guard object to increment a shared reference count in constructor and
decrement it in destructor. This object is then created on stack in both the
main thread (before creating the new thread) and in the thread-function
(i.e. reference count is increased by 2).

If we finish the thread-function by returning from it (falling off the end),
destructor for both objects is called as expected (first the thread-function
local object and then the main thread local object). This case is
illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line 11
-> the test case passes.

On the other hand if we finish the thread-function by using 'pthread_exit'
instead of falling off the end, the destructor for the thread-function local
object is NOT called (although the destructor for main thread local object
is called). This case is illustrated by compiling with the macro
USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.

C++ resource idiom (acquire in constructor, release in destructor) is used
throughout our threaded program. The described behaviour of pthreads is
introducing possibility of a resource leak and potential deadlock. Does
anybody have any ideas what is happening and how to resolve the problem?

Thank you very much for your replies and help,

Cheers,

	Milan


PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
17-DEC-2001 by Ross)

PS1: Note that the reference counting need not be protected by a mutex as it
will never be accessed simultaneously by both threads due to synchronization
using pthread_join.

PS2: The exit4.c file
===================================
/*
 * Test for pthread_exit().
 *
 * Depends on API functions: pthread_create().
 */

#include "test.h"

#ifdef __cplusplus

#define USE_PTHREAD_EXIT
static const int init_counter_value = 3;
static void *ret_value = reinterpret_cast<void *>(1);
static int counter = init_counter_value;

class Guard
{
    const char * const _str;
    int &_ref;
    Guard &operator=(const Guard&);
    Guard(const Guard&);
public:
    Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
        printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
    };
    ~Guard() {
        printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
    };
};


void *
func(void * arg)
{
    Guard g("func", counter);
#ifdef USE_PTHREAD_EXIT
    pthread_exit(arg);
    assert(0); //Never reached with pthread_exit
#endif //USE_PTHREAD_EXIT
    return ret_value;
}


#endif /*__cplusplus */

int main(int, char **)
{
#ifndef __cplusplus
    printf("Test requires C++. Skipped.\n");
#else
    {
        void *ret = 0;
        Guard g("main", counter);
        pthread_t id;
        assert(0 == pthread_create(&id, 0, func, ret_value));
        assert(0 == pthread_join(id, &ret));
        assert(ret == ret_value);
    }
    assert(counter == init_counter_value);
#endif /*__cplusplus */
    return 0;
}
===================================


PS3: Changes to the 'tests/Makefile' (diff file, use patch):
===================================
--- ..\..\pthreads\tests\Makefile	Fri Oct 26 12:12:48 2001
+++ Makefile	Tue Dec 18 14:16:00 2001
@@ -41,7 +41,7 @@
 	  mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass  mutex2.pass
mutex3.pass  \
 	  condvar1.pass  condvar2.pass  condvar2_1.pass  \
 	  exit1.pass  create1.pass  equal1.pass  \
-	  exit2.pass  exit3.pass  \
+	  exit2.pass  exit3.pass exit4.pass \
 	  join0.pass  join1.pass  join2.pass  \
 	  mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass  mutex6r.pass
\
 	  count1.pass  once1.pass  tsd1.pass  \
@@ -186,6 +186,7 @@
 exit1.pass:
 exit2.pass: create1.pass
 exit3.pass: create1.pass
+exit4.pass: create1.pass
 eyal1.pass: tsd1.pass
 inherit1.pass: join1.pass
 join0.pass: create1.pass
===================================

This message may contain privileged and/or confidential information.  If you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender by
e-mail promptly that you have done so.  Thank You.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
  2001-01-11  6:04 Mike Kinghan
@ 2001-12-18  7:00 ` Mike Kinghan
  0 siblings, 0 replies; 32+ messages in thread
From: Mike Kinghan @ 2001-12-18  7:00 UTC (permalink / raw)
  To: 'Gardian, Milan', Pthreads-Win32@Sources.Redhat.Com
  Cc: Ross Johnson (E-mail)

Yeah, I have encountered similar problems. I presume you are using MS VC++
6.0 and that these disappearing destructors affect your release build but
not your debug build?

The cause is apparently a bug in the VC++ 6.0 optimiser. With default
optimisation in release mode, the compiler just convinces itself that it
needn't bother generating those pesky destructors in exception-handling Turn
off the release mode optimisation and you get the destructors back.

This solution is a bit of pain in the arse however, because the affected
PThreadCleanup class is fully exposed in pthread.h, so to make pthread
client code safe from this bug you are going have to forego optimisation for
__all__ of it.

I found that a preferable solution was to hide the implementation of the
cleanup class off in a source module to be built with the pthreads library.
Then you lose the inlining of the cleanup class, which is regretable, and
you need to build the library without optimisation, but at least you can
build you own release code with the usual optimisation.

Mike Kinghan, Systems Union Ltd
www.systemsunion.com  

-----Original Message-----
From: Gardian, Milan [ mailto:Milan.Gardian@LEIBINGER.com ]
Sent: Tuesday, December 18, 2001 2:17 PM
To: Pthreads-Win32@Sources.Redhat.Com
Cc: Ross Johnson (E-mail)
Subject: pthreads VCE: problem with destructor


Hi,

I came across a problem with pthreads VCE: destructors for objects in local
scope (automatic variables on stack) of the thread-function are not called
when using 'pthread_exit' to exit the thread (or when using any function
that eventually throws a C++ exception (because of VCE build) using
ptw32_throw internal function).

To illustrate this point I created a new test case, 'exit4.c'. It uses a C++
guard object to increment a shared reference count in constructor and
decrement it in destructor. This object is then created on stack in both the
main thread (before creating the new thread) and in the thread-function
(i.e. reference count is increased by 2).

If we finish the thread-function by returning from it (falling off the end),
destructor for both objects is called as expected (first the thread-function
local object and then the main thread local object). This case is
illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line 11
-> the test case passes.

On the other hand if we finish the thread-function by using 'pthread_exit'
instead of falling off the end, the destructor for the thread-function local
object is NOT called (although the destructor for main thread local object
is called). This case is illustrated by compiling with the macro
USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.

C++ resource idiom (acquire in constructor, release in destructor) is used
throughout our threaded program. The described behaviour of pthreads is
introducing possibility of a resource leak and potential deadlock. Does
anybody have any ideas what is happening and how to resolve the problem?

Thank you very much for your replies and help,

Cheers,

	Milan


PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
17-DEC-2001 by Ross)

PS1: Note that the reference counting need not be protected by a mutex as it
will never be accessed simultaneously by both threads due to synchronization
using pthread_join.

PS2: The exit4.c file
===================================
/*
 * Test for pthread_exit().
 *
 * Depends on API functions: pthread_create().
 */

#include "test.h"

#ifdef __cplusplus

#define USE_PTHREAD_EXIT
static const int init_counter_value = 3;
static void *ret_value = reinterpret_cast<void *>(1);
static int counter = init_counter_value;

class Guard
{
    const char * const _str;
    int &_ref;
    Guard &operator=(const Guard&);
    Guard(const Guard&);
public:
    Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
        printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
    };
    ~Guard() {
        printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
    };
};


void *
func(void * arg)
{
    Guard g("func", counter);
#ifdef USE_PTHREAD_EXIT
    pthread_exit(arg);
    assert(0); //Never reached with pthread_exit
#endif //USE_PTHREAD_EXIT
    return ret_value;
}


#endif /*__cplusplus */

int main(int, char **)
{
#ifndef __cplusplus
    printf("Test requires C++. Skipped.\n");
#else
    {
        void *ret = 0;
        Guard g("main", counter);
        pthread_t id;
        assert(0 == pthread_create(&id, 0, func, ret_value));
        assert(0 == pthread_join(id, &ret));
        assert(ret == ret_value);
    }
    assert(counter == init_counter_value);
#endif /*__cplusplus */
    return 0;
}
===================================


PS3: Changes to the 'tests/Makefile' (diff file, use patch):
===================================
--- ..\..\pthreads\tests\Makefile	Fri Oct 26 12:12:48 2001
+++ Makefile	Tue Dec 18 14:16:00 2001
@@ -41,7 +41,7 @@
 	  mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass  mutex2.pass
mutex3.pass  \
 	  condvar1.pass  condvar2.pass  condvar2_1.pass  \
 	  exit1.pass  create1.pass  equal1.pass  \
-	  exit2.pass  exit3.pass  \
+	  exit2.pass  exit3.pass exit4.pass \
 	  join0.pass  join1.pass  join2.pass  \
 	  mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass  mutex6r.pass
\
 	  count1.pass  once1.pass  tsd1.pass  \
@@ -186,6 +186,7 @@
 exit1.pass:
 exit2.pass: create1.pass
 exit3.pass: create1.pass
+exit4.pass: create1.pass
 eyal1.pass: tsd1.pass
 inherit1.pass: join1.pass
 join0.pass: create1.pass
===================================

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
@ 2001-03-22 11:41 Bossom, John
  2001-12-20  8:46 ` Bossom, John
  0 siblings, 1 reply; 32+ messages in thread
From: Bossom, John @ 2001-03-22 11:41 UTC (permalink / raw)
  To: 'Alexander Terekhov', pthreads-win32

A well respected opinion, indeed, given he (David Butenhof) is
the author of "Programming with POSIX Threads". 

However, this is an opinion.... it is not reality today. And demanding
a free, open-source, library that was attempting to provide a portable
solution for PTHREADs for win32 developers would lull C++ developers
into a false sense of security and will get a very rude shock when/if
they port their product to UNIX.

As I have already stated, if you base your code on
a non-standard implementation "today", then you are asking for trouble
if you intended on your code to be portable. Even if you demand
this change now, just when do you think you are actually going
to get a portable solution that you can actually use and depend
upon?

I, for one, will not tell my company that we cannot release
a product on all platforms because I am waiting for the POSIX 
and C++ standards committee to comply with my request (then waiting
(possibly years) for the OS implementors to adopt the "new" standard) --- 
I would be out of a job.




-----Original Message-----
From: Alexander Terekhov [mailto:TEREKHOV@de.ibm.com]
Sent: December 20, 2001 9:09 AM
To: pthreads-win32@sources.redhat.com
Subject: Re: pthreads VCE: problem with destructor



> Please do not take my comments out of the context. The original text was
[...]
> I do not wanted the destructors to be run because this is nonportable.
> Before the setjmp/longjmp code the only working implementation for
> mingw32 was the c++ one that i disliked.

OK, just one more try...

Consider the following opinion:

http://groups.google.com/groups?as_umsgid=3A8D120B.73749CEC%40compaq.com

"In any RATIONAL and USEFUL implementation that supports both POSIX threads
and
 C++, there's no different between "calling POSIX cleanup handlers" and
 "throwing a C++ exception", because thread cancellation and exit, and C++
 exceptions, are all instances of an underlying universal platform
exception
 infrastructure. That means that POSIX cleanup handlers will be run when a
 thrown C++ exception propagates through the frame in which the cleanup
handler
 has been pushed; and C++ object destructors will be run when a local
object is
 active in a frame through which a POSIX cancellation or exit propagates.

 The same, of course, must be true for any other language with exceptions
and
 handlers.

 Either the "system" is a "system", or it's a collection of spare parts
that
 happen to have been dumped in the same box. The latter may not explicitly
 violate any standards, and may even be usable with sufficient effort and
 restrictions; but that doesn't make it a good idea.

 System implementors should get this right. Application developers should
 demand it. The days are long gone when exceptions were some arcane thing
that
 only a few weird and non-mainstream languages supported. For a system to
work,
 exceptions must be integrated into the system's basic calling standard
along
 with issues like register usage and the appearance of stack frames.
There's
 simply no excuse for messing this up, and no excuses should be accepted!

 /------------------[ David.Butenhof@compaq.com ]------------------\
 | Compaq Computer Corporation              POSIX Thread Architect |
 |     My book: http://www.awl.com/cseng/titles/0-201-63392-2/     |
 \-----[ http://home.earthlink.net/~anneart/family/dave.html ]-----/"

regards,
alexander.


This message may contain privileged and/or confidential information.  If you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender by
e-mail promptly that you have done so.  Thank You.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
@ 2001-03-22 11:39 Alexander Terekhov
  2001-12-20  6:08 ` Alexander Terekhov
  0 siblings, 1 reply; 32+ messages in thread
From: Alexander Terekhov @ 2001-03-22 11:39 UTC (permalink / raw)
  To: pthreads-win32


> Please do not take my comments out of the context. The original text was
[...]
> I do not wanted the destructors to be run because this is nonportable.
> Before the setjmp/longjmp code the only working implementation for
> mingw32 was the c++ one that i disliked.

OK, just one more try...

Consider the following opinion:

http://groups.google.com/groups?as_umsgid=3A8D120B.73749CEC%40compaq.com

"In any RATIONAL and USEFUL implementation that supports both POSIX threads
and
 C++, there's no different between "calling POSIX cleanup handlers" and
 "throwing a C++ exception", because thread cancellation and exit, and C++
 exceptions, are all instances of an underlying universal platform
exception
 infrastructure. That means that POSIX cleanup handlers will be run when a
 thrown C++ exception propagates through the frame in which the cleanup
handler
 has been pushed; and C++ object destructors will be run when a local
object is
 active in a frame through which a POSIX cancellation or exit propagates.

 The same, of course, must be true for any other language with exceptions
and
 handlers.

 Either the "system" is a "system", or it's a collection of spare parts
that
 happen to have been dumped in the same box. The latter may not explicitly
 violate any standards, and may even be usable with sufficient effort and
 restrictions; but that doesn't make it a good idea.

 System implementors should get this right. Application developers should
 demand it. The days are long gone when exceptions were some arcane thing
that
 only a few weird and non-mainstream languages supported. For a system to
work,
 exceptions must be integrated into the system's basic calling standard
along
 with issues like register usage and the appearance of stack frames.
There's
 simply no excuse for messing this up, and no excuses should be accepted!

 /------------------[ David.Butenhof@compaq.com ]------------------\
 | Compaq Computer Corporation              POSIX Thread Architect |
 |     My book: http://www.awl.com/cseng/titles/0-201-63392-2/     |
 \-----[ http://home.earthlink.net/~anneart/family/dave.html ]-----/"

regards,
alexander.


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
@ 2001-03-22 11:19 Thomas Pfaff
  2001-12-20  4:40 ` Thomas Pfaff
  0 siblings, 1 reply; 32+ messages in thread
From: Thomas Pfaff @ 2001-03-22 11:19 UTC (permalink / raw)
  To: TEREKHOV; +Cc: pthreads-win32




> > This is exactly the reason why i have created the
> > setjmp/longjmp version.
>
> I am really puzzled. Since there is no standard
> PTHREAD C++ bindings that would guarantee things
> such as C++ tack unwinding on thread exit/
> cancellation, any C++ threaded written to exploit
> such things is NOT truly portable. However, there
> is practically no way to make thread cancellation/
> exit work in C++ programs using setjmp/longjmp
> because the C++ standard restricts the LEGAL
> usage of longjmp in *C++* programs:
>
> ISO/IEC 14882:1998(E), Pg 347:
>
> "The function signature longjmp(jmp_buf jbuf, int val)
>  has more restricted behavior in this International
>  Standard. If any automatic objects would be destroyed
>  by a thrown exception transferring control to another
>  (destination) point in the program, then a call to
>  longjmp( jbuf, val) at the throw point that transfers
>  control to the same (destination) point has
>  undefined behavior."
>  ^^^^^^^^^^^^^^^^^^
>
> regards,
> alexander.


Please do not take my comments out of the context. The original text was

*****
> Regardless as Mr. Bossom so well has already stated: I certainly
> wouldn't
> depend on pthread_exit() or pthread_cancel() allowing destructors to run
> to be
> portable though.  Since the primary purpose of this library is to
> enhance
> portability of programs using pthreads, counting on pthread_exit() or
> pthread_cancel() to work in a non-portable way seems self-defeating.

This is exactly the reason why i have created the setjmp/longjmp version.
There may be bugs in it but i think they could be discovered if more would
using it.
*****

I do not wanted the destructors to be run because this is nonportable.
Before the setjmp/longjmp code the only working implementation for
mingw32 was the c++ one that i disliked.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
@ 2001-03-12  5:53 Alexander Terekhov
  2001-12-20  2:35 ` Alexander Terekhov
  0 siblings, 1 reply; 32+ messages in thread
From: Alexander Terekhov @ 2001-03-12  5:53 UTC (permalink / raw)
  To: pthreads-win32



>> Since the primary purpose of this library is to
>> enhance portability of programs using pthreads,
>> counting on pthread_exit() or pthread_cancel()
>> to work in a non-portable way seems self-defeating.

Well, you are certainly allowed NOT to use pthread_exit()
and pthread_cancel() in your C++ programs. As long as
implementation invokes C thread cleanup handlers *IN C*
programs IT IS CONFORMING.

Why do you care how pthread library for C++ implements
it wrt to C++ stack unwinding? As long as you are not
using it (_cancel/_exit) that should not be an issue
for you.

> This is exactly the reason why i have created the
> setjmp/longjmp version.

I am really puzzled. Since there is no standard
PTHREAD C++ bindings that would guarantee things
such as C++ tack unwinding on thread exit/
cancellation, any C++ threaded written to exploit
such things is NOT truly portable. However, there
is practically no way to make thread cancellation/
exit work in C++ programs using setjmp/longjmp
because the C++ standard restricts the LEGAL
usage of longjmp in *C++* programs:

ISO/IEC 14882:1998(E), Pg 347:

"The function signature longjmp(jmp_buf jbuf, int val)
 has more restricted behavior in this International
 Standard. If any automatic objects would be destroyed
 by a thrown exception transferring control to another
 (destination) point in the program, then a call to
 longjmp( jbuf, val) at the throw point that transfers
 control to the same (destination) point has
 undefined behavior."
 ^^^^^^^^^^^^^^^^^^

regards,
alexander.


Thomas Pfaff <tpfaff@gmx.net>@sources.redhat.com on 12/20/2001 10:25:14 AM

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
cc:
Subject:  Re: pthreads VCE: problem with destructor




On Wed, 19 Dec 2001, reentrant wrote:

>
> Due to the nature of the beast just as the responsibility lies with the
> programmer to design the program to "cleanly" (including running
> destructors,
> ad nauseum) exit when exit() is called, it should also be the
> responsibility of
> the programmer to design a thread to cleanly exit with pthread_exit() or
> pthread_cancel() are called.  Just as exit() should not be called in a
> C++
> program if dtors are desired to run neither should pthread_exit() from a
> thread.  IMHO.
>
> I would imagine that exit() was chosen not to be modified to account for
> running C++ destructors for about the same reasons that pthread_exit()
> should
> not account for running C++ destructors.  Dtors not being called in
> these cases
> is and should be expected behavior.
>
> Regardless as Mr. Bossom so well has already stated: I certainly
> wouldn't
> depend on pthread_exit() or pthread_cancel() allowing destructors to run
> to be
> portable though.  Since the primary purpose of this library is to
> enhance
> portability of programs using pthreads, counting on pthread_exit() or
> pthread_cancel() to work in a non-portable way seems self-defeating.

This is exactly the reason why i have created the setjmp/longjmp version.
There may be bugs in it but i think they could be discovered if more would
using it.


> While attempting to allow dtors to be run upon a pthread_exit() or
> pthread_cancel() is certainly a noble goal, it's beyond the scope of the
> pthread library.  It's the programmer's responsibility IMHO.
>
> So, as I hope is obvious by this point :), I am completely in support of
> the
> "nasty hacks" being removed and a clean C interface version of the
> library
> being provided only.

Try the GC stuff and report bugs.

>
> My two cents,
> Dave
>
>
> --- Ross Johnson <rpj@ise.canberra.edu.au> wrote:
> > I sense a rising and ruthless desire to deal with the problem of
> > the exception-based versions of the library. It would certainly
> > be a lot easier if they weren't there, and there are some
> > hacks in pthread.h supporting them that really are nasty.
> >
> > So ... what to do about them?
> >
> > I will firstly put John's warning in the README file
> > and the README.NONPORTABLE file, and on the Web page.
> >
> > Secondly, there is a standard C version of the library courtesy
> > of Thomas Pfaff's contributions. It uses setjmp/longjmp.
> > Does this need to be built differently to work with C++
> > applications (assuming they are written as John suggests they
> > should be)?

No. The only thing you need is to define __CLEANUP_C to avoid the default
handling in pthread.h.

/*
 * define defaults for cleanup code
 */
#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined(
__CLEANUP_C )

#if defined(_MSC_VER)
#define __CLEANUP_SEH
#elif defined(__cplusplus)
#define __CLEANUP_CXX
#else
#define __CLEANUP_C
#endif

#endif

These defaults have been added to be backward compatible and it is time to
remove them.


> > I can try putting it through the VCE run of the
> > test suite as soon as I reinstall my corrupted Windows 98 machine.
> >
> > Thirdly, if possible, consider phasing out all but the VC and GC
> > versions of the library (currently the only standard C versions).
> > That is, phase out the VCE, VSE, and GCE versions.
> >
> > Does anyone wan't to jump up and shout - NO!!
> >
> > Ross
> >
>

Regards,
Thomas




^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-01-24 14:02   ` reentrant
@ 2001-03-10  6:41     ` Thomas Pfaff
  2001-12-20  1:25       ` Thomas Pfaff
  2001-12-19 10:22     ` reentrant
  1 sibling, 1 reply; 32+ messages in thread
From: Thomas Pfaff @ 2001-03-10  6:41 UTC (permalink / raw)
  To: Pthreads-Win32@Sources.Redhat.Com


On Wed, 19 Dec 2001, reentrant wrote:

>
> Due to the nature of the beast just as the responsibility lies with the
> programmer to design the program to "cleanly" (including running
> destructors,
> ad nauseum) exit when exit() is called, it should also be the
> responsibility of
> the programmer to design a thread to cleanly exit with pthread_exit() or
> pthread_cancel() are called.  Just as exit() should not be called in a
> C++
> program if dtors are desired to run neither should pthread_exit() from a
> thread.  IMHO.
>
> I would imagine that exit() was chosen not to be modified to account for
> running C++ destructors for about the same reasons that pthread_exit()
> should
> not account for running C++ destructors.  Dtors not being called in
> these cases
> is and should be expected behavior.
>
> Regardless as Mr. Bossom so well has already stated: I certainly
> wouldn't
> depend on pthread_exit() or pthread_cancel() allowing destructors to run
> to be
> portable though.  Since the primary purpose of this library is to
> enhance
> portability of programs using pthreads, counting on pthread_exit() or
> pthread_cancel() to work in a non-portable way seems self-defeating.

This is exactly the reason why i have created the setjmp/longjmp version.
There may be bugs in it but i think they could be discovered if more would
using it.


> While attempting to allow dtors to be run upon a pthread_exit() or
> pthread_cancel() is certainly a noble goal, it's beyond the scope of the
> pthread library.  It's the programmer's responsibility IMHO.
>
> So, as I hope is obvious by this point :), I am completely in support of
> the
> "nasty hacks" being removed and a clean C interface version of the
> library
> being provided only.

Try the GC stuff and report bugs.

>
> My two cents,
> Dave
>
>
> --- Ross Johnson <rpj@ise.canberra.edu.au> wrote:
> > I sense a rising and ruthless desire to deal with the problem of
> > the exception-based versions of the library. It would certainly
> > be a lot easier if they weren't there, and there are some
> > hacks in pthread.h supporting them that really are nasty.
> >
> > So ... what to do about them?
> >
> > I will firstly put John's warning in the README file
> > and the README.NONPORTABLE file, and on the Web page.
> >
> > Secondly, there is a standard C version of the library courtesy
> > of Thomas Pfaff's contributions. It uses setjmp/longjmp.
> > Does this need to be built differently to work with C++
> > applications (assuming they are written as John suggests they
> > should be)?

No. The only thing you need is to define __CLEANUP_C to avoid the default
handling in pthread.h.

/*
 * define defaults for cleanup code
 */
#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined(
__CLEANUP_C )

#if defined(_MSC_VER)
#define __CLEANUP_SEH
#elif defined(__cplusplus)
#define __CLEANUP_CXX
#else
#define __CLEANUP_C
#endif

#endif

These defaults have been added to be backward compatible and it is time to
remove them.


> > I can try putting it through the VCE run of the
> > test suite as soon as I reinstall my corrupted Windows 98 machine.
> >
> > Thirdly, if possible, consider phasing out all but the VC and GC
> > versions of the library (currently the only standard C versions).
> > That is, phase out the VCE, VSE, and GCE versions.
> >
> > Does anyone wan't to jump up and shout - NO!!
> >
> > Ross
> >
>

Regards,
Thomas

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
@ 2001-02-23  8:35 Bossom, John
  2001-12-19 13:19 ` Bossom, John
  0 siblings, 1 reply; 32+ messages in thread
From: Bossom, John @ 2001-02-23  8:35 UTC (permalink / raw)
  To: 'Alexander Terekhov', pthreads-win32

Well I am sure we all wish for that functionality, don't hold your breath
waiting on Sun Microsystems,HP, IBM, etc. Unix providers supplying this
functionality. (i.e. C++ working in tandem with pthread_cancel or any
other C based functionality for that matter (i.e. longjmp/setjmp, signal
handling, etc)

It wasn't there 3.5 years ago when I came up with the initial pthreads
source code that I contributed to the pthreads-win32.

Putting such functionality into pthreads-win32 would mean that any
code leveraging it will not port to platforms that actually provide
pthreads libraries.

The book "Multithreaded Programming with PTHREADS", by Bil Lewis
and Daniel J. Berg, pages 232-233 gives an overview of the issues
in using C++ and PThreads together. 

I feel your pain (I've been there already)

Sincerely,

John.


-----Original Message-----
From: Alexander Terekhov [mailto:TEREKHOV@de.ibm.com]
Sent: December 19, 2001 2:03 PM
To: pthreads-win32@sources.redhat.com
Subject: RE: pthreads VCE: problem with destructor




> Alexander, it is not clear to me what you are strongly disagreeing
> with... my recommendation? (and it is not solely my recommendation,
> I can quote oodles of books recommending the same approach)

Yes.

> However, pthread_cancel is not documented as working in
> tandem with C++ stack unwinding.

I believe that it should be documented that a version
of pthreads-win32 library meant to be used in C++ programs
DOES work in tandem with C++ stack unwinding. Note that it
has nothing to do with a version of pthreads-win32 library
meant to be used in pure C programs.

> I would not recommend using it in a C++ application.

Personally, I disagree strongly with this approach.
I would ask pthread-lib vendor to provide C++ aware
pthread library, instead.

> To deal with "cancel",
> I would recommend representing a unit of work (i.e. a task)
> as an object that supports it's own ability to "cancel".
> A thread is just a means to an end... you want to do
> a unit of work. A unit of work could be executed directly,
> or within a thread, or tasked through a thread pool. The
> easiest, consistent, method of cancelling it is to cancel
> the task, not the "worker" trying to do the task.

Jobs/Tasks are OK, but they are not threads.
pthread_cancel and _exit are designed for threads.

> The only advantage that pthread_cancel has (on unix, that is)
> is that some basic C library methods that block are cancellable
> by pthread_cancel. You don't have this luxury on win32 unless you
> re-write the C runtime library with pthreads-win32.

Well, for example, how about waiting on condition
variable? That is a cancellation point that works
even with pthreads-win32. I do not want to replace
it with modified predicates which would include
"me->canceled()" flag. I do not want to know which
mutexes need to be locked and which condition variables
need to be signaled/broadcasted for a particular thread
to archive the effect meant to be provided by the
pthread_cancel.

I just want that in addition to C thread cleanup
handlers, thread cancel/exit would invoke C++
destructors and "catch(...)" handlers.

regards,
alexander.


"Bossom, John" <John.Bossom@Cognos.COM>@sources.redhat.com on 12/19/2001
03:00:58 PM

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   Alexander Terekhov/Germany/IBM@IBMDE,
      pthreads-win32@sources.redhat.com
cc:
Subject:  RE: pthreads VCE: problem with destructor



Alexander, it is not clear to me what you are strongly disagreeing
with... my recommendation? (and it is not solely my recommendation,
I can quote oodles of books recommending the same approach)

However, pthread_cancel is not documented as working in
tandem with C++ stack unwinding. I would not recommend
using it in a C++ application.

To deal with "cancel",
I would recommend representing a unit of work (i.e. a task)
as an object that supports it's own ability to "cancel".
A thread is just a means to an end... you want to do
a unit of work. A unit of work could be executed directly,
or within a thread, or tasked through a thread pool. The
easiest, consistent, method of cancelling it is to cancel
the task, not the "worker" trying to do the task.
The only advantage that pthread_cancel has (on unix, that is)
is that some basic C library methods that block are cancellable
by pthread_cancel. You don't have this luxury on win32 unless you
re-write the C runtime library with pthreads-win32.

Just my 2 cents.

Good Luck,

John.


-----Original Message-----
From: Alexander Terekhov [mailto:TEREKHOV@de.ibm.com]
Sent: December 19, 2001 7:41 AM
To: pthreads-win32@sources.redhat.com
Subject: Re: pthreads VCE: problem with destructor



> > Recommended approach when using C++ in conjunction with pthreads is to
> > NEVER use pthread_exit... you should have your code return to your
> > thread mainline (use exceptions if you choose) and simply "return"
> > from the thread mainline.

How about pthread_cancel? Are you saying that I should
never use it in a threaded C++ program for the same
reason(s) as pthread_exit?

Personally, I disagree strongly with this approach.

FYI:

http://groups.google.com/groups?as_umsgid=362DCB0D.230D900%40zko.dec.com
http://groups.google.com/groups?as_umsgid=kZ7h7.623%24bB1.30401%40news.cpqco

rp.net
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0004.HTM#cancel_excep_sec
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0001.HTM#index_x_53

"Several Threads Library features and most Threads Library
 identifiers are provided as C language macros. As such,
 their definitions may not be available in other languages.
 Developers working in other languages will have to provide
 their own declarations of functions and constants, and
 features such as TRY/CATCH exception handling and POSIX
 push/pop cleanup handlers may be completely unavailable
 (although it may be possible to provide similar
 functionality using native exception handling facilities).
 Note that in this context, C++ is a non-C language;
 while the C language macros may compile successfully
 under C++, TRY/CATCH and push/pop cleanup handlers
 are not supported for C++ code. C++ code should use
 object descructors and C++ exception handlers. "
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0011.HTM#excep_defs

"Exception         Definition
 ================  ===================================
 pthread_cancel_e  Thread cancelation in progress
 .
 .
 .
 pthread_exit_e    Thread exiting using pthread_exit()"

regards,
alexander.


Ross Johnson <rpj@ise.canberra.edu.au>@sources.redhat.com on 12/19/2001
12:37:59 PM

Please respond to rpj@ise.canberra.edu.au

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Bossom, John" <John.Bossom@Cognos.COM>
cc:   "'Gardian, Milan'" <Milan.Gardian@LEIBINGER.com>,
      "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
Subject:  Re: pthreads VCE: problem with destructor



I sense a rising and ruthless desire to deal with the problem of
the exception-based versions of the library. It would certainly
be a lot easier if they weren't there, and there are some
hacks in pthread.h supporting them that really are nasty.

So ... what to do about them?

I will firstly put John's warning in the README file
and the README.NONPORTABLE file, and on the Web page.

Secondly, there is a standard C version of the library courtesy
of Thomas Pfaff's contributions. It uses setjmp/longjmp.
Does this need to be built differently to work with C++
applications (assuming they are written as John suggests they
should be)? I can try putting it through the VCE run of the
test suite as soon as I reinstall my corrupted Windows 98 machine.

Thirdly, if possible, consider phasing out all but the VC and GC
versions of the library (currently the only standard C versions).
That is, phase out the VCE, VSE, and GCE versions.

Does anyone wan't to jump up and shout - NO!!

Ross

"Bossom, John" wrote:
>
> <Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)
>
> You are entering dark territory here. You are assuming that
> Operating System primitives actually cooperate with C++ primitives (i.e
> exception handling, implicit
> call of local destructors)
> This is not the case. At the time of implementation of pthread_win32
> (original version) pthread_exit on UNIX did NOT call the C++ destructors
> and perform graceful stack unwinding. pthread_exit basically did an end
run
> exit and locally called all registered pthread cleanup methods.
>
> Recommended approach when using C++ in conjunction with pthreads is to
> NEVER use pthread_exit... you should have your code return to your
> thread mainline (use exceptions if you choose) and simply "return"
> from the thread mainline.
>
> If you (Ross) implement this marrying of C++ stack-unwinding with
> pthread_exit, I suggest you
> document that it is not typical behavior and you can expect that if you
port
> your code back
> to various unix platforms that actually support pthreads natively, you
> will encounter exactly the same problem.
>
> -----Original Message-----
> From: Gardian, Milan [mailto:Milan.Gardian@LEIBINGER.com]
> Sent: December 18, 2001 9:17 AM
> To: Pthreads-Win32@Sources.Redhat.Com
> Cc: Ross Johnson (E-mail)
> Subject: pthreads VCE: problem with destructor
>
> Hi,
>
> I came across a problem with pthreads VCE: destructors for objects in
local
> scope (automatic variables on stack) of the thread-function are not
called
> when using 'pthread_exit' to exit the thread (or when using any function
> that eventually throws a C++ exception (because of VCE build) using
> ptw32_throw internal function).
>
> To illustrate this point I created a new test case, 'exit4.c'. It uses a
C++
> guard object to increment a shared reference count in constructor and
> decrement it in destructor. This object is then created on stack in both
the
> main thread (before creating the new thread) and in the thread-function
> (i.e. reference count is increased by 2).
>
> If we finish the thread-function by returning from it (falling off the
end),
> destructor for both objects is called as expected (first the
thread-function
> local object and then the main thread local object). This case is
> illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line
11
> -> the test case passes.
>
> On the other hand if we finish the thread-function by using
'pthread_exit'
> instead of falling off the end, the destructor for the thread-function
local
> object is NOT called (although the destructor for main thread local
object
> is called). This case is illustrated by compiling with the macro
> USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.
>
> C++ resource idiom (acquire in constructor, release in destructor) is
used
> throughout our threaded program. The described behaviour of pthreads is
> introducing possibility of a resource leak and potential deadlock. Does
> anybody have any ideas what is happening and how to resolve the problem?
>
> Thank you very much for your replies and help,
>
> Cheers,
>
>         Milan
>
> PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
> June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
> 17-DEC-2001 by Ross)
>
> PS1: Note that the reference counting need not be protected by a mutex as
it
> will never be accessed simultaneously by both threads due to
synchronization
> using pthread_join.
>
> PS2: The exit4.c file
> ===================================
> /*
>  * Test for pthread_exit().
>  *
>  * Depends on API functions: pthread_create().
>  */
>
> #include "test.h"
>
> #ifdef __cplusplus
>
> #define USE_PTHREAD_EXIT
> static const int init_counter_value = 3;
> static void *ret_value = reinterpret_cast<void *>(1);
> static int counter = init_counter_value;
>
> class Guard
> {
>     const char * const _str;
>     int &_ref;
>     Guard &operator=(const Guard&);
>     Guard(const Guard&);
> public:
>     Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
>         printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
>     };
>     ~Guard() {
>         printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
>     };
> };
>
> void *
> func(void * arg)
> {
>     Guard g("func", counter);
> #ifdef USE_PTHREAD_EXIT
>     pthread_exit(arg);
>     assert(0); //Never reached with pthread_exit
> #endif //USE_PTHREAD_EXIT
>     return ret_value;
> }
>
> #endif /*__cplusplus */
>
> int main(int, char **)
> {
> #ifndef __cplusplus
>     printf("Test requires C++. Skipped.\n");
> #else
>     {
>         void *ret = 0;
>         Guard g("main", counter);
>         pthread_t id;
>         assert(0 == pthread_create(&id, 0, func, ret_value));
>         assert(0 == pthread_join(id, &ret));
>         assert(ret == ret_value);
>     }
>     assert(counter == init_counter_value);
> #endif /*__cplusplus */
>     return 0;
> }
> ===================================
>
> PS3: Changes to the 'tests/Makefile' (diff file, use patch):
> ===================================
> --- ..\..\pthreads\tests\Makefile       Fri Oct 26 12:12:48 2001
> +++ Makefile    Tue Dec 18 14:16:00 2001
> @@ -41,7 +41,7 @@
>           mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass
mutex2.pass
> mutex3.pass  \
>           condvar1.pass  condvar2.pass  condvar2_1.pass  \
>           exit1.pass  create1.pass  equal1.pass  \
> -         exit2.pass  exit3.pass  \
> +         exit2.pass  exit3.pass exit4.pass \
>           join0.pass  join1.pass  join2.pass  \
>           mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass
mutex6r.pass
> \
>           count1.pass  once1.pass  tsd1.pass  \
> @@ -186,6 +186,7 @@
>  exit1.pass:
>  exit2.pass: create1.pass
>  exit3.pass: create1.pass
> +exit4.pass: create1.pass
>  eyal1.pass: tsd1.pass
>  inherit1.pass: join1.pass
>  join0.pass: create1.pass
> ===================================
>
> This message may contain privileged and/or confidential information.  If
you
> have received this e-mail in error or are not the intended recipient, you
> may not use, copy, disseminate, or distribute it; do not open any
> attachments, delete it immediately from your system and notify the sender
by
> e-mail promptly that you have done so.  Thank You.



This message may contain privileged and/or confidential information.  If
you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender
by
e-mail promptly that you have done so.  Thank You.



This message may contain privileged and/or confidential information.  If you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender by
e-mail promptly that you have done so.  Thank You.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
@ 2001-02-01  6:46 Alexander Terekhov
  2001-12-19 11:30 ` Alexander Terekhov
  0 siblings, 1 reply; 32+ messages in thread
From: Alexander Terekhov @ 2001-02-01  6:46 UTC (permalink / raw)
  To: pthreads-win32



> Due to the nature of the beast just as the responsibility lies with the
> programmer to design the program to "cleanly" (including running
destructors,
> ad nauseum) exit when exit() is called, it should also be the
responsibility of
> the programmer to design a thread to cleanly exit with pthread_exit() or
> pthread_cancel() are called.  Just as exit() should not be called in a
C++
> program if dtors are desired to run neither should pthread_exit() from a
> thread.  IMHO.

The C++ standard says:

"The function exit() has additional behavior in this
 International Standard:

 - First, objects with static storage duration are
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   destroyed and functions registered by calling
   ^^^^^^^^^
   atexit are called. Objects with static storage
   duration are destroyed in the reverse order of
   the completion of their constructor.
   (Automatic objects are not destroyed
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   as a result of calling exit().) "

but that has nothing to do with behavior
of pthread_cancel/exit wrt destruction of
automatic objects and C thread cleanup
handlers (see the last paragraph below).

The POSIX standard (non-normative Rationale volume) says:

"Thread Cancelation Cleanup Handlers
 .
 .
 .
 The alternative to providing these simple cancelation cleanup
 handlers (whose only use is for cleaning up when a thread is
 canceled) is to define a general exception package that could
 be used for handling and cleaning up after hardware traps and
 software-detected errors. This was too far removed from the
 charter of providing threads to handle asynchrony. However,
 it is an explicit goal of IEEE Std 1003.1-2001 to be compatible
 with existing exception facilities and languages having
 exceptions.

 The interaction of this facility and other procedure-based or
 language-level exception facilities is unspecified in this
 version of IEEE Std 1003.1-2001. However, it is intended that
 it be possible for an implementation to define the relationship
 between these cancelation cleanup handlers and Ada, C++, or
 other language-level exception handling facilities.

 It was suggested that the cancelation cleanup handlers should
 also be called when the process exits or calls the exec function.
 This was rejected partly due to the performance problem caused
 by having to call the cancelation cleanup handlers of every
 thread before the operation could continue. The other reason was
 that the only state expected to be cleaned up by the cancelation
 cleanup handlers would be the intraprocess state. Any handlers
 that are to clean up the interprocess state would be registered
 with atexit ( ). "

regards,
alexander.


reentrant <reentrant@yahoo.com>@sources.redhat.com on 12/19/2001 07:22:13
PM

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
cc:
Subject:  Re: pthreads VCE: problem with destructor




Due to the nature of the beast just as the responsibility lies with the
programmer to design the program to "cleanly" (including running
destructors,
ad nauseum) exit when exit() is called, it should also be the
responsibility of
the programmer to design a thread to cleanly exit with pthread_exit() or
pthread_cancel() are called.  Just as exit() should not be called in a C++
program if dtors are desired to run neither should pthread_exit() from a
thread.  IMHO.

I would imagine that exit() was chosen not to be modified to account for
running C++ destructors for about the same reasons that pthread_exit()
should
not account for running C++ destructors.  Dtors not being called in these
cases
is and should be expected behavior.

Regardless as Mr. Bossom so well has already stated: I certainly wouldn't
depend on pthread_exit() or pthread_cancel() allowing destructors to run to
be
portable though.  Since the primary purpose of this library is to enhance
portability of programs using pthreads, counting on pthread_exit() or
pthread_cancel() to work in a non-portable way seems self-defeating.

Simple sample programs included in the distribution of pthreads to
demonstrate
the technique might help.  Maybe something like:

class AppExit
{
public:
    AppExit( int status ) :
        m_status( status )
    {}
    ~AppExit( void )
    {}

    int GetStatus( void ) const
    { return m_status; }

private:
    int m_status;
};

void function( void )
{
    // blah blah blah

    if( true )
    {
        // Error.  blah blah blah failed.
        throw AppExit( 3 );
    }

    // blah blah blah succeeded,
    // continue execution as usual...
}

int main( void )
{
    try
    {
        // Call functions and what not.
        // If an abrupt exit is required
        // throw AppExit to unwind the stack
        // and exit in the catch block.
        function( );
    }
    catch( const AppExit& ae )
    {
        // App requested to exit.
        // exit() itself not used here so
        // global and other dtors will run
        // correctly.
        return ae.GetStatus( );
    }
    return 0;
}

Replace "AppExit" with something like "ThreadExit" and "main" with the name
of
the thread entry point function, account for the return value type
difference
and there's an example for cleanly exiting a thread (I'm confident the
similar
parallel can be figured out without explicitly spelling it out :).

I'm not even going to attempt to touch the complexities or nuances of
issues
related to clean cancellation in any language or on any OS :).  I'd instead
recommend against cancellation altogether and recommend using a mechanism
to
signal the thread to exit itself (like throwing an exception above or
something).  But that's another story and just an opinion.  Cancellation is
covered in plenty depth elsewhere.

While attempting to allow dtors to be run upon a pthread_exit() or
pthread_cancel() is certainly a noble goal, it's beyond the scope of the
pthread library.  It's the programmer's responsibility IMHO.

So, as I hope is obvious by this point :), I am completely in support of
the
"nasty hacks" being removed and a clean C interface version of the library
being provided only.

My two cents,
Dave


--- Ross Johnson <rpj@ise.canberra.edu.au> wrote:
> I sense a rising and ruthless desire to deal with the problem of
> the exception-based versions of the library. It would certainly
> be a lot easier if they weren't there, and there are some
> hacks in pthread.h supporting them that really are nasty.
>
> So ... what to do about them?
>
> I will firstly put John's warning in the README file
> and the README.NONPORTABLE file, and on the Web page.
>
> Secondly, there is a standard C version of the library courtesy
> of Thomas Pfaff's contributions. It uses setjmp/longjmp.
> Does this need to be built differently to work with C++
> applications (assuming they are written as John suggests they
> should be)? I can try putting it through the VCE run of the
> test suite as soon as I reinstall my corrupted Windows 98 machine.
>
> Thirdly, if possible, consider phasing out all but the VC and GC
> versions of the library (currently the only standard C versions).
> That is, phase out the VCE, VSE, and GCE versions.
>
> Does anyone wan't to jump up and shout - NO!!
>
> Ross
>


__________________________________________________
Do You Yahoo!?
Check out Yahoo! Shopping and Yahoo! Auctions for all of
your unique holiday gifts! Buy at http://shopping.yahoo.com
or bid at http://auctions.yahoo.com



^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
@ 2001-01-24 21:42 Alexander Terekhov
  2001-12-19 11:01 ` Alexander Terekhov
  0 siblings, 1 reply; 32+ messages in thread
From: Alexander Terekhov @ 2001-01-24 21:42 UTC (permalink / raw)
  To: pthreads-win32



> Alexander, it is not clear to me what you are strongly disagreeing
> with... my recommendation? (and it is not solely my recommendation,
> I can quote oodles of books recommending the same approach)

Yes.

> However, pthread_cancel is not documented as working in
> tandem with C++ stack unwinding.

I believe that it should be documented that a version
of pthreads-win32 library meant to be used in C++ programs
DOES work in tandem with C++ stack unwinding. Note that it
has nothing to do with a version of pthreads-win32 library
meant to be used in pure C programs.

> I would not recommend using it in a C++ application.

Personally, I disagree strongly with this approach.
I would ask pthread-lib vendor to provide C++ aware
pthread library, instead.

> To deal with "cancel",
> I would recommend representing a unit of work (i.e. a task)
> as an object that supports it's own ability to "cancel".
> A thread is just a means to an end... you want to do
> a unit of work. A unit of work could be executed directly,
> or within a thread, or tasked through a thread pool. The
> easiest, consistent, method of cancelling it is to cancel
> the task, not the "worker" trying to do the task.

Jobs/Tasks are OK, but they are not threads.
pthread_cancel and _exit are designed for threads.

> The only advantage that pthread_cancel has (on unix, that is)
> is that some basic C library methods that block are cancellable
> by pthread_cancel. You don't have this luxury on win32 unless you
> re-write the C runtime library with pthreads-win32.

Well, for example, how about waiting on condition
variable? That is a cancellation point that works
even with pthreads-win32. I do not want to replace
it with modified predicates which would include
"me->canceled()" flag. I do not want to know which
mutexes need to be locked and which condition variables
need to be signaled/broadcasted for a particular thread
to archive the effect meant to be provided by the
pthread_cancel.

I just want that in addition to C thread cleanup
handlers, thread cancel/exit would invoke C++
destructors and "catch(...)" handlers.

regards,
alexander.


"Bossom, John" <John.Bossom@Cognos.COM>@sources.redhat.com on 12/19/2001
03:00:58 PM

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   Alexander Terekhov/Germany/IBM@IBMDE,
      pthreads-win32@sources.redhat.com
cc:
Subject:  RE: pthreads VCE: problem with destructor



Alexander, it is not clear to me what you are strongly disagreeing
with... my recommendation? (and it is not solely my recommendation,
I can quote oodles of books recommending the same approach)

However, pthread_cancel is not documented as working in
tandem with C++ stack unwinding. I would not recommend
using it in a C++ application.

To deal with "cancel",
I would recommend representing a unit of work (i.e. a task)
as an object that supports it's own ability to "cancel".
A thread is just a means to an end... you want to do
a unit of work. A unit of work could be executed directly,
or within a thread, or tasked through a thread pool. The
easiest, consistent, method of cancelling it is to cancel
the task, not the "worker" trying to do the task.
The only advantage that pthread_cancel has (on unix, that is)
is that some basic C library methods that block are cancellable
by pthread_cancel. You don't have this luxury on win32 unless you
re-write the C runtime library with pthreads-win32.

Just my 2 cents.

Good Luck,

John.


-----Original Message-----
From: Alexander Terekhov [mailto:TEREKHOV@de.ibm.com]
Sent: December 19, 2001 7:41 AM
To: pthreads-win32@sources.redhat.com
Subject: Re: pthreads VCE: problem with destructor



> > Recommended approach when using C++ in conjunction with pthreads is to
> > NEVER use pthread_exit... you should have your code return to your
> > thread mainline (use exceptions if you choose) and simply "return"
> > from the thread mainline.

How about pthread_cancel? Are you saying that I should
never use it in a threaded C++ program for the same
reason(s) as pthread_exit?

Personally, I disagree strongly with this approach.

FYI:

http://groups.google.com/groups?as_umsgid=362DCB0D.230D900%40zko.dec.com
http://groups.google.com/groups?as_umsgid=kZ7h7.623%24bB1.30401%40news.cpqco

rp.net
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0004.HTM#cancel_excep_sec
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0001.HTM#index_x_53

"Several Threads Library features and most Threads Library
 identifiers are provided as C language macros. As such,
 their definitions may not be available in other languages.
 Developers working in other languages will have to provide
 their own declarations of functions and constants, and
 features such as TRY/CATCH exception handling and POSIX
 push/pop cleanup handlers may be completely unavailable
 (although it may be possible to provide similar
 functionality using native exception handling facilities).
 Note that in this context, C++ is a non-C language;
 while the C language macros may compile successfully
 under C++, TRY/CATCH and push/pop cleanup handlers
 are not supported for C++ code. C++ code should use
 object descructors and C++ exception handlers. "
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB

TE/DOCU0011.HTM#excep_defs

"Exception         Definition
 ================  ===================================
 pthread_cancel_e  Thread cancelation in progress
 .
 .
 .
 pthread_exit_e    Thread exiting using pthread_exit()"

regards,
alexander.


Ross Johnson <rpj@ise.canberra.edu.au>@sources.redhat.com on 12/19/2001
12:37:59 PM

Please respond to rpj@ise.canberra.edu.au

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Bossom, John" <John.Bossom@Cognos.COM>
cc:   "'Gardian, Milan'" <Milan.Gardian@LEIBINGER.com>,
      "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
Subject:  Re: pthreads VCE: problem with destructor



I sense a rising and ruthless desire to deal with the problem of
the exception-based versions of the library. It would certainly
be a lot easier if they weren't there, and there are some
hacks in pthread.h supporting them that really are nasty.

So ... what to do about them?

I will firstly put John's warning in the README file
and the README.NONPORTABLE file, and on the Web page.

Secondly, there is a standard C version of the library courtesy
of Thomas Pfaff's contributions. It uses setjmp/longjmp.
Does this need to be built differently to work with C++
applications (assuming they are written as John suggests they
should be)? I can try putting it through the VCE run of the
test suite as soon as I reinstall my corrupted Windows 98 machine.

Thirdly, if possible, consider phasing out all but the VC and GC
versions of the library (currently the only standard C versions).
That is, phase out the VCE, VSE, and GCE versions.

Does anyone wan't to jump up and shout - NO!!

Ross

"Bossom, John" wrote:
>
> <Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)
>
> You are entering dark territory here. You are assuming that
> Operating System primitives actually cooperate with C++ primitives (i.e
> exception handling, implicit
> call of local destructors)
> This is not the case. At the time of implementation of pthread_win32
> (original version) pthread_exit on UNIX did NOT call the C++ destructors
> and perform graceful stack unwinding. pthread_exit basically did an end
run
> exit and locally called all registered pthread cleanup methods.
>
> Recommended approach when using C++ in conjunction with pthreads is to
> NEVER use pthread_exit... you should have your code return to your
> thread mainline (use exceptions if you choose) and simply "return"
> from the thread mainline.
>
> If you (Ross) implement this marrying of C++ stack-unwinding with
> pthread_exit, I suggest you
> document that it is not typical behavior and you can expect that if you
port
> your code back
> to various unix platforms that actually support pthreads natively, you
> will encounter exactly the same problem.
>
> -----Original Message-----
> From: Gardian, Milan [mailto:Milan.Gardian@LEIBINGER.com]
> Sent: December 18, 2001 9:17 AM
> To: Pthreads-Win32@Sources.Redhat.Com
> Cc: Ross Johnson (E-mail)
> Subject: pthreads VCE: problem with destructor
>
> Hi,
>
> I came across a problem with pthreads VCE: destructors for objects in
local
> scope (automatic variables on stack) of the thread-function are not
called
> when using 'pthread_exit' to exit the thread (or when using any function
> that eventually throws a C++ exception (because of VCE build) using
> ptw32_throw internal function).
>
> To illustrate this point I created a new test case, 'exit4.c'. It uses a
C++
> guard object to increment a shared reference count in constructor and
> decrement it in destructor. This object is then created on stack in both
the
> main thread (before creating the new thread) and in the thread-function
> (i.e. reference count is increased by 2).
>
> If we finish the thread-function by returning from it (falling off the
end),
> destructor for both objects is called as expected (first the
thread-function
> local object and then the main thread local object). This case is
> illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line
11
> -> the test case passes.
>
> On the other hand if we finish the thread-function by using
'pthread_exit'
> instead of falling off the end, the destructor for the thread-function
local
> object is NOT called (although the destructor for main thread local
object
> is called). This case is illustrated by compiling with the macro
> USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.
>
> C++ resource idiom (acquire in constructor, release in destructor) is
used
> throughout our threaded program. The described behaviour of pthreads is
> introducing possibility of a resource leak and potential deadlock. Does
> anybody have any ideas what is happening and how to resolve the problem?
>
> Thank you very much for your replies and help,
>
> Cheers,
>
>         Milan
>
> PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
> June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
> 17-DEC-2001 by Ross)
>
> PS1: Note that the reference counting need not be protected by a mutex as
it
> will never be accessed simultaneously by both threads due to
synchronization
> using pthread_join.
>
> PS2: The exit4.c file
> ===================================
> /*
>  * Test for pthread_exit().
>  *
>  * Depends on API functions: pthread_create().
>  */
>
> #include "test.h"
>
> #ifdef __cplusplus
>
> #define USE_PTHREAD_EXIT
> static const int init_counter_value = 3;
> static void *ret_value = reinterpret_cast<void *>(1);
> static int counter = init_counter_value;
>
> class Guard
> {
>     const char * const _str;
>     int &_ref;
>     Guard &operator=(const Guard&);
>     Guard(const Guard&);
> public:
>     Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
>         printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
>     };
>     ~Guard() {
>         printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
>     };
> };
>
> void *
> func(void * arg)
> {
>     Guard g("func", counter);
> #ifdef USE_PTHREAD_EXIT
>     pthread_exit(arg);
>     assert(0); //Never reached with pthread_exit
> #endif //USE_PTHREAD_EXIT
>     return ret_value;
> }
>
> #endif /*__cplusplus */
>
> int main(int, char **)
> {
> #ifndef __cplusplus
>     printf("Test requires C++. Skipped.\n");
> #else
>     {
>         void *ret = 0;
>         Guard g("main", counter);
>         pthread_t id;
>         assert(0 == pthread_create(&id, 0, func, ret_value));
>         assert(0 == pthread_join(id, &ret));
>         assert(ret == ret_value);
>     }
>     assert(counter == init_counter_value);
> #endif /*__cplusplus */
>     return 0;
> }
> ===================================
>
> PS3: Changes to the 'tests/Makefile' (diff file, use patch):
> ===================================
> --- ..\..\pthreads\tests\Makefile       Fri Oct 26 12:12:48 2001
> +++ Makefile    Tue Dec 18 14:16:00 2001
> @@ -41,7 +41,7 @@
>           mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass
mutex2.pass
> mutex3.pass  \
>           condvar1.pass  condvar2.pass  condvar2_1.pass  \
>           exit1.pass  create1.pass  equal1.pass  \
> -         exit2.pass  exit3.pass  \
> +         exit2.pass  exit3.pass exit4.pass \
>           join0.pass  join1.pass  join2.pass  \
>           mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass
mutex6r.pass
> \
>           count1.pass  once1.pass  tsd1.pass  \
> @@ -186,6 +186,7 @@
>  exit1.pass:
>  exit2.pass: create1.pass
>  exit3.pass: create1.pass
> +exit4.pass: create1.pass
>  eyal1.pass: tsd1.pass
>  inherit1.pass: join1.pass
>  join0.pass: create1.pass
> ===================================
>
> This message may contain privileged and/or confidential information.  If
you
> have received this e-mail in error or are not the intended recipient, you
> may not use, copy, disseminate, or distribute it; do not open any
> attachments, delete it immediately from your system and notify the sender
by
> e-mail promptly that you have done so.  Thank You.



This message may contain privileged and/or confidential information.  If
you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender
by
e-mail promptly that you have done so.  Thank You.



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-01-15  7:40 ` Ross Johnson
@ 2001-01-24 14:02   ` reentrant
  2001-03-10  6:41     ` Thomas Pfaff
  2001-12-19 10:22     ` reentrant
  2001-12-19  3:38   ` Ross Johnson
  1 sibling, 2 replies; 32+ messages in thread
From: reentrant @ 2001-01-24 14:02 UTC (permalink / raw)
  To: Pthreads-Win32@Sources.Redhat.Com


Due to the nature of the beast just as the responsibility lies with the
programmer to design the program to "cleanly" (including running destructors,
ad nauseum) exit when exit() is called, it should also be the responsibility of
the programmer to design a thread to cleanly exit with pthread_exit() or
pthread_cancel() are called.  Just as exit() should not be called in a C++
program if dtors are desired to run neither should pthread_exit() from a
thread.  IMHO.

I would imagine that exit() was chosen not to be modified to account for
running C++ destructors for about the same reasons that pthread_exit() should
not account for running C++ destructors.  Dtors not being called in these cases
is and should be expected behavior.

Regardless as Mr. Bossom so well has already stated: I certainly wouldn't
depend on pthread_exit() or pthread_cancel() allowing destructors to run to be
portable though.  Since the primary purpose of this library is to enhance
portability of programs using pthreads, counting on pthread_exit() or
pthread_cancel() to work in a non-portable way seems self-defeating.

Simple sample programs included in the distribution of pthreads to demonstrate
the technique might help.  Maybe something like:

class AppExit
{
public:
    AppExit( int status ) :
        m_status( status )
    {}
    ~AppExit( void )
    {}

    int GetStatus( void ) const
    { return m_status; }

private:
    int m_status;
};

void function( void )
{
    // blah blah blah

    if( true )
    {
        // Error.  blah blah blah failed.
        throw AppExit( 3 );
    }

    // blah blah blah succeeded, 
    // continue execution as usual...
}

int main( void )
{
    try
    {
        // Call functions and what not.
        // If an abrupt exit is required
        // throw AppExit to unwind the stack
        // and exit in the catch block.
        function( );
    }
    catch( const AppExit& ae )
    {
        // App requested to exit.
        // exit() itself not used here so
        // global and other dtors will run
        // correctly.
        return ae.GetStatus( );
    }
    return 0;
}

Replace "AppExit" with something like "ThreadExit" and "main" with the name of
the thread entry point function, account for the return value type difference
and there's an example for cleanly exiting a thread (I'm confident the similar
parallel can be figured out without explicitly spelling it out :).

I'm not even going to attempt to touch the complexities or nuances of issues
related to clean cancellation in any language or on any OS :).  I'd instead
recommend against cancellation altogether and recommend using a mechanism to
signal the thread to exit itself (like throwing an exception above or
something).  But that's another story and just an opinion.  Cancellation is
covered in plenty depth elsewhere.

While attempting to allow dtors to be run upon a pthread_exit() or
pthread_cancel() is certainly a noble goal, it's beyond the scope of the
pthread library.  It's the programmer's responsibility IMHO.

So, as I hope is obvious by this point :), I am completely in support of the
"nasty hacks" being removed and a clean C interface version of the library
being provided only.

My two cents,
Dave


--- Ross Johnson <rpj@ise.canberra.edu.au> wrote:
> I sense a rising and ruthless desire to deal with the problem of
> the exception-based versions of the library. It would certainly
> be a lot easier if they weren't there, and there are some
> hacks in pthread.h supporting them that really are nasty.
> 
> So ... what to do about them?
> 
> I will firstly put John's warning in the README file
> and the README.NONPORTABLE file, and on the Web page.
> 
> Secondly, there is a standard C version of the library courtesy
> of Thomas Pfaff's contributions. It uses setjmp/longjmp.
> Does this need to be built differently to work with C++
> applications (assuming they are written as John suggests they
> should be)? I can try putting it through the VCE run of the
> test suite as soon as I reinstall my corrupted Windows 98 machine.
> 
> Thirdly, if possible, consider phasing out all but the VC and GC
> versions of the library (currently the only standard C versions).
> That is, phase out the VCE, VSE, and GCE versions.
> 
> Does anyone wan't to jump up and shout - NO!!
> 
> Ross
> 


__________________________________________________
Do You Yahoo!?
Check out Yahoo! Shopping and Yahoo! Auctions for all of
your unique holiday gifts! Buy at http://shopping.yahoo.com
or bid at http://auctions.yahoo.com

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
@ 2001-01-16 16:48 Bossom, John
  2001-12-19  6:02 ` Bossom, John
  0 siblings, 1 reply; 32+ messages in thread
From: Bossom, John @ 2001-01-16 16:48 UTC (permalink / raw)
  To: 'Alexander Terekhov', pthreads-win32

Alexander, it is not clear to me what you are strongly disagreeing
with... my recommendation? (and it is not solely my recommendation,
I can quote oodles of books recommending the same approach)

However, pthread_cancel is not documented as working in
tandem with C++ stack unwinding. I would not recommend
using it in a C++ application.

To deal with "cancel",
I would recommend representing a unit of work (i.e. a task)
as an object that supports it's own ability to "cancel".
A thread is just a means to an end... you want to do
a unit of work. A unit of work could be executed directly,
or within a thread, or tasked through a thread pool. The
easiest, consistent, method of cancelling it is to cancel
the task, not the "worker" trying to do the task.
The only advantage that pthread_cancel has (on unix, that is)
is that some basic C library methods that block are cancellable
by pthread_cancel. You don't have this luxury on win32 unless you
re-write the C runtime library with pthreads-win32.

Just my 2 cents.

Good Luck,

John.


-----Original Message-----
From: Alexander Terekhov [mailto:TEREKHOV@de.ibm.com]
Sent: December 19, 2001 7:41 AM
To: pthreads-win32@sources.redhat.com
Subject: Re: pthreads VCE: problem with destructor



> > Recommended approach when using C++ in conjunction with pthreads is to
> > NEVER use pthread_exit... you should have your code return to your
> > thread mainline (use exceptions if you choose) and simply "return"
> > from the thread mainline.

How about pthread_cancel? Are you saying that I should
never use it in a threaded C++ program for the same
reason(s) as pthread_exit?

Personally, I disagree strongly with this approach.

FYI:

http://groups.google.com/groups?as_umsgid=362DCB0D.230D900%40zko.dec.com
http://groups.google.com/groups?as_umsgid=kZ7h7.623%24bB1.30401%40news.cpqco
rp.net
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB
TE/DOCU0004.HTM#cancel_excep_sec
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB
TE/DOCU0001.HTM#index_x_53

"Several Threads Library features and most Threads Library
 identifiers are provided as C language macros. As such,
 their definitions may not be available in other languages.
 Developers working in other languages will have to provide
 their own declarations of functions and constants, and
 features such as TRY/CATCH exception handling and POSIX
 push/pop cleanup handlers may be completely unavailable
 (although it may be possible to provide similar
 functionality using native exception handling facilities).
 Note that in this context, C++ is a non-C language;
 while the C language macros may compile successfully
 under C++, TRY/CATCH and push/pop cleanup handlers
 are not supported for C++ code. C++ code should use
 object descructors and C++ exception handlers. "
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RB
TE/DOCU0011.HTM#excep_defs

"Exception         Definition
 ================  ===================================
 pthread_cancel_e  Thread cancelation in progress
 .
 .
 .
 pthread_exit_e    Thread exiting using pthread_exit()"

regards,
alexander.


Ross Johnson <rpj@ise.canberra.edu.au>@sources.redhat.com on 12/19/2001
12:37:59 PM

Please respond to rpj@ise.canberra.edu.au

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Bossom, John" <John.Bossom@Cognos.COM>
cc:   "'Gardian, Milan'" <Milan.Gardian@LEIBINGER.com>,
      "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
Subject:  Re: pthreads VCE: problem with destructor



I sense a rising and ruthless desire to deal with the problem of
the exception-based versions of the library. It would certainly
be a lot easier if they weren't there, and there are some
hacks in pthread.h supporting them that really are nasty.

So ... what to do about them?

I will firstly put John's warning in the README file
and the README.NONPORTABLE file, and on the Web page.

Secondly, there is a standard C version of the library courtesy
of Thomas Pfaff's contributions. It uses setjmp/longjmp.
Does this need to be built differently to work with C++
applications (assuming they are written as John suggests they
should be)? I can try putting it through the VCE run of the
test suite as soon as I reinstall my corrupted Windows 98 machine.

Thirdly, if possible, consider phasing out all but the VC and GC
versions of the library (currently the only standard C versions).
That is, phase out the VCE, VSE, and GCE versions.

Does anyone wan't to jump up and shout - NO!!

Ross

"Bossom, John" wrote:
>
> <Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)
>
> You are entering dark territory here. You are assuming that
> Operating System primitives actually cooperate with C++ primitives (i.e
> exception handling, implicit
> call of local destructors)
> This is not the case. At the time of implementation of pthread_win32
> (original version) pthread_exit on UNIX did NOT call the C++ destructors
> and perform graceful stack unwinding. pthread_exit basically did an end
run
> exit and locally called all registered pthread cleanup methods.
>
> Recommended approach when using C++ in conjunction with pthreads is to
> NEVER use pthread_exit... you should have your code return to your
> thread mainline (use exceptions if you choose) and simply "return"
> from the thread mainline.
>
> If you (Ross) implement this marrying of C++ stack-unwinding with
> pthread_exit, I suggest you
> document that it is not typical behavior and you can expect that if you
port
> your code back
> to various unix platforms that actually support pthreads natively, you
> will encounter exactly the same problem.
>
> -----Original Message-----
> From: Gardian, Milan [mailto:Milan.Gardian@LEIBINGER.com]
> Sent: December 18, 2001 9:17 AM
> To: Pthreads-Win32@Sources.Redhat.Com
> Cc: Ross Johnson (E-mail)
> Subject: pthreads VCE: problem with destructor
>
> Hi,
>
> I came across a problem with pthreads VCE: destructors for objects in
local
> scope (automatic variables on stack) of the thread-function are not
called
> when using 'pthread_exit' to exit the thread (or when using any function
> that eventually throws a C++ exception (because of VCE build) using
> ptw32_throw internal function).
>
> To illustrate this point I created a new test case, 'exit4.c'. It uses a
C++
> guard object to increment a shared reference count in constructor and
> decrement it in destructor. This object is then created on stack in both
the
> main thread (before creating the new thread) and in the thread-function
> (i.e. reference count is increased by 2).
>
> If we finish the thread-function by returning from it (falling off the
end),
> destructor for both objects is called as expected (first the
thread-function
> local object and then the main thread local object). This case is
> illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line
11
> -> the test case passes.
>
> On the other hand if we finish the thread-function by using
'pthread_exit'
> instead of falling off the end, the destructor for the thread-function
local
> object is NOT called (although the destructor for main thread local
object
> is called). This case is illustrated by compiling with the macro
> USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.
>
> C++ resource idiom (acquire in constructor, release in destructor) is
used
> throughout our threaded program. The described behaviour of pthreads is
> introducing possibility of a resource leak and potential deadlock. Does
> anybody have any ideas what is happening and how to resolve the problem?
>
> Thank you very much for your replies and help,
>
> Cheers,
>
>         Milan
>
> PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
> June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
> 17-DEC-2001 by Ross)
>
> PS1: Note that the reference counting need not be protected by a mutex as
it
> will never be accessed simultaneously by both threads due to
synchronization
> using pthread_join.
>
> PS2: The exit4.c file
> ===================================
> /*
>  * Test for pthread_exit().
>  *
>  * Depends on API functions: pthread_create().
>  */
>
> #include "test.h"
>
> #ifdef __cplusplus
>
> #define USE_PTHREAD_EXIT
> static const int init_counter_value = 3;
> static void *ret_value = reinterpret_cast<void *>(1);
> static int counter = init_counter_value;
>
> class Guard
> {
>     const char * const _str;
>     int &_ref;
>     Guard &operator=(const Guard&);
>     Guard(const Guard&);
> public:
>     Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
>         printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
>     };
>     ~Guard() {
>         printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
>     };
> };
>
> void *
> func(void * arg)
> {
>     Guard g("func", counter);
> #ifdef USE_PTHREAD_EXIT
>     pthread_exit(arg);
>     assert(0); //Never reached with pthread_exit
> #endif //USE_PTHREAD_EXIT
>     return ret_value;
> }
>
> #endif /*__cplusplus */
>
> int main(int, char **)
> {
> #ifndef __cplusplus
>     printf("Test requires C++. Skipped.\n");
> #else
>     {
>         void *ret = 0;
>         Guard g("main", counter);
>         pthread_t id;
>         assert(0 == pthread_create(&id, 0, func, ret_value));
>         assert(0 == pthread_join(id, &ret));
>         assert(ret == ret_value);
>     }
>     assert(counter == init_counter_value);
> #endif /*__cplusplus */
>     return 0;
> }
> ===================================
>
> PS3: Changes to the 'tests/Makefile' (diff file, use patch):
> ===================================
> --- ..\..\pthreads\tests\Makefile       Fri Oct 26 12:12:48 2001
> +++ Makefile    Tue Dec 18 14:16:00 2001
> @@ -41,7 +41,7 @@
>           mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass
mutex2.pass
> mutex3.pass  \
>           condvar1.pass  condvar2.pass  condvar2_1.pass  \
>           exit1.pass  create1.pass  equal1.pass  \
> -         exit2.pass  exit3.pass  \
> +         exit2.pass  exit3.pass exit4.pass \
>           join0.pass  join1.pass  join2.pass  \
>           mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass
mutex6r.pass
> \
>           count1.pass  once1.pass  tsd1.pass  \
> @@ -186,6 +186,7 @@
>  exit1.pass:
>  exit2.pass: create1.pass
>  exit3.pass: create1.pass
> +exit4.pass: create1.pass
>  eyal1.pass: tsd1.pass
>  inherit1.pass: join1.pass
>  join0.pass: create1.pass
> ===================================
>
> This message may contain privileged and/or confidential information.  If
you
> have received this e-mail in error or are not the intended recipient, you
> may not use, copy, disseminate, or distribute it; do not open any
> attachments, delete it immediately from your system and notify the sender
by
> e-mail promptly that you have done so.  Thank You.



This message may contain privileged and/or confidential information.  If you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender by
e-mail promptly that you have done so.  Thank You.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
@ 2001-01-16  7:38 Alexander Terekhov
  2001-12-19  4:40 ` Alexander Terekhov
  0 siblings, 1 reply; 32+ messages in thread
From: Alexander Terekhov @ 2001-01-16  7:38 UTC (permalink / raw)
  To: pthreads-win32


> > Recommended approach when using C++ in conjunction with pthreads is to
> > NEVER use pthread_exit... you should have your code return to your
> > thread mainline (use exceptions if you choose) and simply "return"
> > from the thread mainline.

How about pthread_cancel? Are you saying that I should
never use it in a threaded C++ program for the same
reason(s) as pthread_exit?

Personally, I disagree strongly with this approach.

FYI:

http://groups.google.com/groups?as_umsgid=362DCB0D.230D900%40zko.dec.com
http://groups.google.com/groups?as_umsgid=kZ7h7.623%24bB1.30401%40news.cpqcorp.net
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RBTE/DOCU0004.HTM#cancel_excep_sec
http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RBTE/DOCU0001.HTM#index_x_53

"Several Threads Library features and most Threads Library
 identifiers are provided as C language macros. As such,
 their definitions may not be available in other languages.
 Developers working in other languages will have to provide
 their own declarations of functions and constants, and
 features such as TRY/CATCH exception handling and POSIX
 push/pop cleanup handlers may be completely unavailable
 (although it may be possible to provide similar
 functionality using native exception handling facilities).
 Note that in this context, C++ is a non-C language;
 while the C language macros may compile successfully
 under C++, TRY/CATCH and push/pop cleanup handlers
 are not supported for C++ code. C++ code should use
 object descructors and C++ exception handlers. "
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_HTML/ARH9RBTE/DOCU0011.HTM#excep_defs

"Exception         Definition
 ================  ===================================
 pthread_cancel_e  Thread cancelation in progress
 .
 .
 .
 pthread_exit_e    Thread exiting using pthread_exit()"

regards,
alexander.


Ross Johnson <rpj@ise.canberra.edu.au>@sources.redhat.com on 12/19/2001
12:37:59 PM

Please respond to rpj@ise.canberra.edu.au

Sent by:  pthreads-win32-owner@sources.redhat.com


To:   "Bossom, John" <John.Bossom@Cognos.COM>
cc:   "'Gardian, Milan'" <Milan.Gardian@LEIBINGER.com>,
      "Pthreads-Win32@Sources.Redhat.Com"
      <pthreads-win32@sources.redhat.com>
Subject:  Re: pthreads VCE: problem with destructor



I sense a rising and ruthless desire to deal with the problem of
the exception-based versions of the library. It would certainly
be a lot easier if they weren't there, and there are some
hacks in pthread.h supporting them that really are nasty.

So ... what to do about them?

I will firstly put John's warning in the README file
and the README.NONPORTABLE file, and on the Web page.

Secondly, there is a standard C version of the library courtesy
of Thomas Pfaff's contributions. It uses setjmp/longjmp.
Does this need to be built differently to work with C++
applications (assuming they are written as John suggests they
should be)? I can try putting it through the VCE run of the
test suite as soon as I reinstall my corrupted Windows 98 machine.

Thirdly, if possible, consider phasing out all but the VC and GC
versions of the library (currently the only standard C versions).
That is, phase out the VCE, VSE, and GCE versions.

Does anyone wan't to jump up and shout - NO!!

Ross

"Bossom, John" wrote:
>
> <Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)
>
> You are entering dark territory here. You are assuming that
> Operating System primitives actually cooperate with C++ primitives (i.e
> exception handling, implicit
> call of local destructors)
> This is not the case. At the time of implementation of pthread_win32
> (original version) pthread_exit on UNIX did NOT call the C++ destructors
> and perform graceful stack unwinding. pthread_exit basically did an end
run
> exit and locally called all registered pthread cleanup methods.
>
> Recommended approach when using C++ in conjunction with pthreads is to
> NEVER use pthread_exit... you should have your code return to your
> thread mainline (use exceptions if you choose) and simply "return"
> from the thread mainline.
>
> If you (Ross) implement this marrying of C++ stack-unwinding with
> pthread_exit, I suggest you
> document that it is not typical behavior and you can expect that if you
port
> your code back
> to various unix platforms that actually support pthreads natively, you
> will encounter exactly the same problem.
>
> -----Original Message-----
> From: Gardian, Milan [mailto:Milan.Gardian@LEIBINGER.com]
> Sent: December 18, 2001 9:17 AM
> To: Pthreads-Win32@Sources.Redhat.Com
> Cc: Ross Johnson (E-mail)
> Subject: pthreads VCE: problem with destructor
>
> Hi,
>
> I came across a problem with pthreads VCE: destructors for objects in
local
> scope (automatic variables on stack) of the thread-function are not
called
> when using 'pthread_exit' to exit the thread (or when using any function
> that eventually throws a C++ exception (because of VCE build) using
> ptw32_throw internal function).
>
> To illustrate this point I created a new test case, 'exit4.c'. It uses a
C++
> guard object to increment a shared reference count in constructor and
> decrement it in destructor. This object is then created on stack in both
the
> main thread (before creating the new thread) and in the thread-function
> (i.e. reference count is increased by 2).
>
> If we finish the thread-function by returning from it (falling off the
end),
> destructor for both objects is called as expected (first the
thread-function
> local object and then the main thread local object). This case is
> illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line
11
> -> the test case passes.
>
> On the other hand if we finish the thread-function by using
'pthread_exit'
> instead of falling off the end, the destructor for the thread-function
local
> object is NOT called (although the destructor for main thread local
object
> is called). This case is illustrated by compiling with the macro
> USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.
>
> C++ resource idiom (acquire in constructor, release in destructor) is
used
> throughout our threaded program. The described behaviour of pthreads is
> introducing possibility of a resource leak and potential deadlock. Does
> anybody have any ideas what is happening and how to resolve the problem?
>
> Thank you very much for your replies and help,
>
> Cheers,
>
>         Milan
>
> PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
> June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
> 17-DEC-2001 by Ross)
>
> PS1: Note that the reference counting need not be protected by a mutex as
it
> will never be accessed simultaneously by both threads due to
synchronization
> using pthread_join.
>
> PS2: The exit4.c file
> ===================================
> /*
>  * Test for pthread_exit().
>  *
>  * Depends on API functions: pthread_create().
>  */
>
> #include "test.h"
>
> #ifdef __cplusplus
>
> #define USE_PTHREAD_EXIT
> static const int init_counter_value = 3;
> static void *ret_value = reinterpret_cast<void *>(1);
> static int counter = init_counter_value;
>
> class Guard
> {
>     const char * const _str;
>     int &_ref;
>     Guard &operator=(const Guard&);
>     Guard(const Guard&);
> public:
>     Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
>         printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
>     };
>     ~Guard() {
>         printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
>     };
> };
>
> void *
> func(void * arg)
> {
>     Guard g("func", counter);
> #ifdef USE_PTHREAD_EXIT
>     pthread_exit(arg);
>     assert(0); //Never reached with pthread_exit
> #endif //USE_PTHREAD_EXIT
>     return ret_value;
> }
>
> #endif /*__cplusplus */
>
> int main(int, char **)
> {
> #ifndef __cplusplus
>     printf("Test requires C++. Skipped.\n");
> #else
>     {
>         void *ret = 0;
>         Guard g("main", counter);
>         pthread_t id;
>         assert(0 == pthread_create(&id, 0, func, ret_value));
>         assert(0 == pthread_join(id, &ret));
>         assert(ret == ret_value);
>     }
>     assert(counter == init_counter_value);
> #endif /*__cplusplus */
>     return 0;
> }
> ===================================
>
> PS3: Changes to the 'tests/Makefile' (diff file, use patch):
> ===================================
> --- ..\..\pthreads\tests\Makefile       Fri Oct 26 12:12:48 2001
> +++ Makefile    Tue Dec 18 14:16:00 2001
> @@ -41,7 +41,7 @@
>           mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass
mutex2.pass
> mutex3.pass  \
>           condvar1.pass  condvar2.pass  condvar2_1.pass  \
>           exit1.pass  create1.pass  equal1.pass  \
> -         exit2.pass  exit3.pass  \
> +         exit2.pass  exit3.pass exit4.pass \
>           join0.pass  join1.pass  join2.pass  \
>           mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass
mutex6r.pass
> \
>           count1.pass  once1.pass  tsd1.pass  \
> @@ -186,6 +186,7 @@
>  exit1.pass:
>  exit2.pass: create1.pass
>  exit3.pass: create1.pass
> +exit4.pass: create1.pass
>  eyal1.pass: tsd1.pass
>  inherit1.pass: join1.pass
>  join0.pass: create1.pass
> ===================================
>
> This message may contain privileged and/or confidential information.  If
you
> have received this e-mail in error or are not the intended recipient, you
> may not use, copy, disseminate, or distribute it; do not open any
> attachments, delete it immediately from your system and notify the sender
by
> e-mail promptly that you have done so.  Thank You.



^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
@ 2001-01-16  1:18 Gardian, Milan
  2001-12-19  4:05 ` Gardian, Milan
  0 siblings, 1 reply; 32+ messages in thread
From: Gardian, Milan @ 2001-01-16  1:18 UTC (permalink / raw)
  To: Mike Kinghan, Pthreads-Win32@Sources.Redhat.Com
  Cc: Ross Johnson (E-mail), John Bossom (E-mail)

Hi Mike,

> Yeah, I have encountered similar problems. I presume
> you are using MS VC++ 6.0 and that these disappearing
> destructors affect your release build but not your
> debug build?

Just wanted to let you know that the problem occurs in debug build as well.
I tried two things:

1. the pthreads distribution, compiled using the command-line VC++
compiler/linker (that contains the full debug info, no optimisations) ->
added a test 'exit4.c' that fails, as described in my previous mail

2. pthreads library compiled from VC++ GUI environment (pthreads.dsp + a
test project). This was a bit more complex than the 'exit4.c' test but also
failed - in both debug (no optimisations) and release builds

I eventually tracked the problem down to

  extern "C"

versus

  extern

function declaration+definition. If the exception is thrown from a function
that was exported as extern "C" from the DLL, destructor is not called
(stack rollback is not performed). On the other hand if the exception is
thrown from a function exported as extern (C++ name mangling and co.), there
is no problem at all (full stack rollback -> destructor call).

Anyway I liked the contribution from John Bossom and will support the
removal of VCE version of pthreads from the library as suggested by Ross
Johnson. I think the C++ stuff introduces more problems than it fixes...

Cheers,

	Milan

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: pthreads VCE: problem with destructor
  2001-01-11  7:04 Bossom, John
@ 2001-01-15  7:40 ` Ross Johnson
  2001-01-24 14:02   ` reentrant
  2001-12-19  3:38   ` Ross Johnson
  2001-12-18 12:22 ` Bossom, John
  1 sibling, 2 replies; 32+ messages in thread
From: Ross Johnson @ 2001-01-15  7:40 UTC (permalink / raw)
  To: Bossom, John; +Cc: 'Gardian, Milan', Pthreads-Win32@Sources.Redhat.Com

I sense a rising and ruthless desire to deal with the problem of
the exception-based versions of the library. It would certainly
be a lot easier if they weren't there, and there are some
hacks in pthread.h supporting them that really are nasty.

So ... what to do about them?

I will firstly put John's warning in the README file
and the README.NONPORTABLE file, and on the Web page.

Secondly, there is a standard C version of the library courtesy
of Thomas Pfaff's contributions. It uses setjmp/longjmp.
Does this need to be built differently to work with C++
applications (assuming they are written as John suggests they
should be)? I can try putting it through the VCE run of the
test suite as soon as I reinstall my corrupted Windows 98 machine.

Thirdly, if possible, consider phasing out all but the VC and GC
versions of the library (currently the only standard C versions).
That is, phase out the VCE, VSE, and GCE versions.

Does anyone wan't to jump up and shout - NO!!

Ross

"Bossom, John" wrote:
> 
> <Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)
> 
> You are entering dark territory here. You are assuming that
> Operating System primitives actually cooperate with C++ primitives (i.e
> exception handling, implicit
> call of local destructors)
> This is not the case. At the time of implementation of pthread_win32
> (original version) pthread_exit on UNIX did NOT call the C++ destructors
> and perform graceful stack unwinding. pthread_exit basically did an end run
> exit and locally called all registered pthread cleanup methods.
> 
> Recommended approach when using C++ in conjunction with pthreads is to
> NEVER use pthread_exit... you should have your code return to your
> thread mainline (use exceptions if you choose) and simply "return"
> from the thread mainline.
> 
> If you (Ross) implement this marrying of C++ stack-unwinding with
> pthread_exit, I suggest you
> document that it is not typical behavior and you can expect that if you port
> your code back
> to various unix platforms that actually support pthreads natively, you
> will encounter exactly the same problem.
> 
> -----Original Message-----
> From: Gardian, Milan [mailto:Milan.Gardian@LEIBINGER.com]
> Sent: December 18, 2001 9:17 AM
> To: Pthreads-Win32@Sources.Redhat.Com
> Cc: Ross Johnson (E-mail)
> Subject: pthreads VCE: problem with destructor
> 
> Hi,
> 
> I came across a problem with pthreads VCE: destructors for objects in local
> scope (automatic variables on stack) of the thread-function are not called
> when using 'pthread_exit' to exit the thread (or when using any function
> that eventually throws a C++ exception (because of VCE build) using
> ptw32_throw internal function).
> 
> To illustrate this point I created a new test case, 'exit4.c'. It uses a C++
> guard object to increment a shared reference count in constructor and
> decrement it in destructor. This object is then created on stack in both the
> main thread (before creating the new thread) and in the thread-function
> (i.e. reference count is increased by 2).
> 
> If we finish the thread-function by returning from it (falling off the end),
> destructor for both objects is called as expected (first the thread-function
> local object and then the main thread local object). This case is
> illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line 11
> -> the test case passes.
> 
> On the other hand if we finish the thread-function by using 'pthread_exit'
> instead of falling off the end, the destructor for the thread-function local
> object is NOT called (although the destructor for main thread local object
> is called). This case is illustrated by compiling with the macro
> USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.
> 
> C++ resource idiom (acquire in constructor, release in destructor) is used
> throughout our threaded program. The described behaviour of pthreads is
> introducing possibility of a resource leak and potential deadlock. Does
> anybody have any ideas what is happening and how to resolve the problem?
> 
> Thank you very much for your replies and help,
> 
> Cheers,
> 
>         Milan
> 
> PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
> June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
> 17-DEC-2001 by Ross)
> 
> PS1: Note that the reference counting need not be protected by a mutex as it
> will never be accessed simultaneously by both threads due to synchronization
> using pthread_join.
> 
> PS2: The exit4.c file
> ===================================
> /*
>  * Test for pthread_exit().
>  *
>  * Depends on API functions: pthread_create().
>  */
> 
> #include "test.h"
> 
> #ifdef __cplusplus
> 
> #define USE_PTHREAD_EXIT
> static const int init_counter_value = 3;
> static void *ret_value = reinterpret_cast<void *>(1);
> static int counter = init_counter_value;
> 
> class Guard
> {
>     const char * const _str;
>     int &_ref;
>     Guard &operator=(const Guard&);
>     Guard(const Guard&);
> public:
>     Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
>         printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
>     };
>     ~Guard() {
>         printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
>     };
> };
> 
> void *
> func(void * arg)
> {
>     Guard g("func", counter);
> #ifdef USE_PTHREAD_EXIT
>     pthread_exit(arg);
>     assert(0); //Never reached with pthread_exit
> #endif //USE_PTHREAD_EXIT
>     return ret_value;
> }
> 
> #endif /*__cplusplus */
> 
> int main(int, char **)
> {
> #ifndef __cplusplus
>     printf("Test requires C++. Skipped.\n");
> #else
>     {
>         void *ret = 0;
>         Guard g("main", counter);
>         pthread_t id;
>         assert(0 == pthread_create(&id, 0, func, ret_value));
>         assert(0 == pthread_join(id, &ret));
>         assert(ret == ret_value);
>     }
>     assert(counter == init_counter_value);
> #endif /*__cplusplus */
>     return 0;
> }
> ===================================
> 
> PS3: Changes to the 'tests/Makefile' (diff file, use patch):
> ===================================
> --- ..\..\pthreads\tests\Makefile       Fri Oct 26 12:12:48 2001
> +++ Makefile    Tue Dec 18 14:16:00 2001
> @@ -41,7 +41,7 @@
>           mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass  mutex2.pass
> mutex3.pass  \
>           condvar1.pass  condvar2.pass  condvar2_1.pass  \
>           exit1.pass  create1.pass  equal1.pass  \
> -         exit2.pass  exit3.pass  \
> +         exit2.pass  exit3.pass exit4.pass \
>           join0.pass  join1.pass  join2.pass  \
>           mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass  mutex6r.pass
> \
>           count1.pass  once1.pass  tsd1.pass  \
> @@ -186,6 +186,7 @@
>  exit1.pass:
>  exit2.pass: create1.pass
>  exit3.pass: create1.pass
> +exit4.pass: create1.pass
>  eyal1.pass: tsd1.pass
>  inherit1.pass: join1.pass
>  join0.pass: create1.pass
> ===================================
> 
> This message may contain privileged and/or confidential information.  If you
> have received this e-mail in error or are not the intended recipient, you
> may not use, copy, disseminate, or distribute it; do not open any
> attachments, delete it immediately from your system and notify the sender by
> e-mail promptly that you have done so.  Thank You.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
@ 2001-01-11  7:04 Bossom, John
  2001-01-15  7:40 ` Ross Johnson
  2001-12-18 12:22 ` Bossom, John
  0 siblings, 2 replies; 32+ messages in thread
From: Bossom, John @ 2001-01-11  7:04 UTC (permalink / raw)
  To: 'Gardian, Milan', Pthreads-Win32@Sources.Redhat.Com
  Cc: Ross Johnson (E-mail)

<Yes - I'm not going to lurk over this one... Hi Ross - I'm still here)

You are entering dark territory here. You are assuming that
Operating System primitives actually cooperate with C++ primitives (i.e
exception handling, implicit
call of local destructors)
This is not the case. At the time of implementation of pthread_win32
(original version) pthread_exit on UNIX did NOT call the C++ destructors
and perform graceful stack unwinding. pthread_exit basically did an end run
exit and locally called all registered pthread cleanup methods.

Recommended approach when using C++ in conjunction with pthreads is to
NEVER use pthread_exit... you should have your code return to your
thread mainline (use exceptions if you choose) and simply "return"
from the thread mainline.

If you (Ross) implement this marrying of C++ stack-unwinding with
pthread_exit, I suggest you
document that it is not typical behavior and you can expect that if you port
your code back
to various unix platforms that actually support pthreads natively, you
will encounter exactly the same problem.


-----Original Message-----
From: Gardian, Milan [mailto:Milan.Gardian@LEIBINGER.com]
Sent: December 18, 2001 9:17 AM
To: Pthreads-Win32@Sources.Redhat.Com
Cc: Ross Johnson (E-mail)
Subject: pthreads VCE: problem with destructor


Hi,

I came across a problem with pthreads VCE: destructors for objects in local
scope (automatic variables on stack) of the thread-function are not called
when using 'pthread_exit' to exit the thread (or when using any function
that eventually throws a C++ exception (because of VCE build) using
ptw32_throw internal function).

To illustrate this point I created a new test case, 'exit4.c'. It uses a C++
guard object to increment a shared reference count in constructor and
decrement it in destructor. This object is then created on stack in both the
main thread (before creating the new thread) and in the thread-function
(i.e. reference count is increased by 2).

If we finish the thread-function by returning from it (falling off the end),
destructor for both objects is called as expected (first the thread-function
local object and then the main thread local object). This case is
illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line 11
-> the test case passes.

On the other hand if we finish the thread-function by using 'pthread_exit'
instead of falling off the end, the destructor for the thread-function local
object is NOT called (although the destructor for main thread local object
is called). This case is illustrated by compiling with the macro
USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.

C++ resource idiom (acquire in constructor, release in destructor) is used
throughout our threaded program. The described behaviour of pthreads is
introducing possibility of a resource leak and potential deadlock. Does
anybody have any ideas what is happening and how to resolve the problem?

Thank you very much for your replies and help,

Cheers,

	Milan


PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
17-DEC-2001 by Ross)

PS1: Note that the reference counting need not be protected by a mutex as it
will never be accessed simultaneously by both threads due to synchronization
using pthread_join.

PS2: The exit4.c file
===================================
/*
 * Test for pthread_exit().
 *
 * Depends on API functions: pthread_create().
 */

#include "test.h"

#ifdef __cplusplus

#define USE_PTHREAD_EXIT
static const int init_counter_value = 3;
static void *ret_value = reinterpret_cast<void *>(1);
static int counter = init_counter_value;

class Guard
{
    const char * const _str;
    int &_ref;
    Guard &operator=(const Guard&);
    Guard(const Guard&);
public:
    Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
        printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
    };
    ~Guard() {
        printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
    };
};


void *
func(void * arg)
{
    Guard g("func", counter);
#ifdef USE_PTHREAD_EXIT
    pthread_exit(arg);
    assert(0); //Never reached with pthread_exit
#endif //USE_PTHREAD_EXIT
    return ret_value;
}


#endif /*__cplusplus */

int main(int, char **)
{
#ifndef __cplusplus
    printf("Test requires C++. Skipped.\n");
#else
    {
        void *ret = 0;
        Guard g("main", counter);
        pthread_t id;
        assert(0 == pthread_create(&id, 0, func, ret_value));
        assert(0 == pthread_join(id, &ret));
        assert(ret == ret_value);
    }
    assert(counter == init_counter_value);
#endif /*__cplusplus */
    return 0;
}
===================================


PS3: Changes to the 'tests/Makefile' (diff file, use patch):
===================================
--- ..\..\pthreads\tests\Makefile	Fri Oct 26 12:12:48 2001
+++ Makefile	Tue Dec 18 14:16:00 2001
@@ -41,7 +41,7 @@
 	  mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass  mutex2.pass
mutex3.pass  \
 	  condvar1.pass  condvar2.pass  condvar2_1.pass  \
 	  exit1.pass  create1.pass  equal1.pass  \
-	  exit2.pass  exit3.pass  \
+	  exit2.pass  exit3.pass exit4.pass \
 	  join0.pass  join1.pass  join2.pass  \
 	  mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass  mutex6r.pass
\
 	  count1.pass  once1.pass  tsd1.pass  \
@@ -186,6 +186,7 @@
 exit1.pass:
 exit2.pass: create1.pass
 exit3.pass: create1.pass
+exit4.pass: create1.pass
 eyal1.pass: tsd1.pass
 inherit1.pass: join1.pass
 join0.pass: create1.pass
===================================

This message may contain privileged and/or confidential information.  If you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate, or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender by
e-mail promptly that you have done so.  Thank You.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* RE: pthreads VCE: problem with destructor
@ 2001-01-11  6:04 Mike Kinghan
  2001-12-18  7:00 ` Mike Kinghan
  0 siblings, 1 reply; 32+ messages in thread
From: Mike Kinghan @ 2001-01-11  6:04 UTC (permalink / raw)
  To: 'Gardian, Milan', Pthreads-Win32@Sources.Redhat.Com
  Cc: Ross Johnson (E-mail)

Yeah, I have encountered similar problems. I presume you are using MS VC++
6.0 and that these disappearing destructors affect your release build but
not your debug build?

The cause is apparently a bug in the VC++ 6.0 optimiser. With default
optimisation in release mode, the compiler just convinces itself that it
needn't bother generating those pesky destructors in exception-handling Turn
off the release mode optimisation and you get the destructors back.

This solution is a bit of pain in the arse however, because the affected
PThreadCleanup class is fully exposed in pthread.h, so to make pthread
client code safe from this bug you are going have to forego optimisation for
__all__ of it.

I found that a preferable solution was to hide the implementation of the
cleanup class off in a source module to be built with the pthreads library.
Then you lose the inlining of the cleanup class, which is regretable, and
you need to build the library without optimisation, but at least you can
build you own release code with the usual optimisation.

Mike Kinghan, Systems Union Ltd
www.systemsunion.com  

-----Original Message-----
From: Gardian, Milan [mailto:Milan.Gardian@LEIBINGER.com]
Sent: Tuesday, December 18, 2001 2:17 PM
To: Pthreads-Win32@Sources.Redhat.Com
Cc: Ross Johnson (E-mail)
Subject: pthreads VCE: problem with destructor


Hi,

I came across a problem with pthreads VCE: destructors for objects in local
scope (automatic variables on stack) of the thread-function are not called
when using 'pthread_exit' to exit the thread (or when using any function
that eventually throws a C++ exception (because of VCE build) using
ptw32_throw internal function).

To illustrate this point I created a new test case, 'exit4.c'. It uses a C++
guard object to increment a shared reference count in constructor and
decrement it in destructor. This object is then created on stack in both the
main thread (before creating the new thread) and in the thread-function
(i.e. reference count is increased by 2).

If we finish the thread-function by returning from it (falling off the end),
destructor for both objects is called as expected (first the thread-function
local object and then the main thread local object). This case is
illustrated by commenting out the macro USE_PTHREAD_EXIT in exit4.c, line 11
-> the test case passes.

On the other hand if we finish the thread-function by using 'pthread_exit'
instead of falling off the end, the destructor for the thread-function local
object is NOT called (although the destructor for main thread local object
is called). This case is illustrated by compiling with the macro
USE_PTHREAD_EXIT in exit4.c, line 11 -> the test case fails.

C++ resource idiom (acquire in constructor, release in destructor) is used
throughout our threaded program. The described behaviour of pthreads is
introducing possibility of a resource leak and potential deadlock. Does
anybody have any ideas what is happening and how to resolve the problem?

Thank you very much for your replies and help,

Cheers,

	Milan


PS0: My config -> SMP 2 x PIII/500, W2k SP1, VC++ 6 SP4, Platform SDK
June/2001, pthreads-latest-2001_12_17 (snaphost of the CVS taken on
17-DEC-2001 by Ross)

PS1: Note that the reference counting need not be protected by a mutex as it
will never be accessed simultaneously by both threads due to synchronization
using pthread_join.

PS2: The exit4.c file
===================================
/*
 * Test for pthread_exit().
 *
 * Depends on API functions: pthread_create().
 */

#include "test.h"

#ifdef __cplusplus

#define USE_PTHREAD_EXIT
static const int init_counter_value = 3;
static void *ret_value = reinterpret_cast<void *>(1);
static int counter = init_counter_value;

class Guard
{
    const char * const _str;
    int &_ref;
    Guard &operator=(const Guard&);
    Guard(const Guard&);
public:
    Guard(const char * const str, int &ref) : _str(str), _ref(ref) {
        printf("Construct %s [%d->%d]\n", _str, _ref, _ref+++1);
    };
    ~Guard() {
        printf("~Destruct %s [%d->%d]\n", _str, _ref, _ref---1);
    };
};


void *
func(void * arg)
{
    Guard g("func", counter);
#ifdef USE_PTHREAD_EXIT
    pthread_exit(arg);
    assert(0); //Never reached with pthread_exit
#endif //USE_PTHREAD_EXIT
    return ret_value;
}


#endif /*__cplusplus */

int main(int, char **)
{
#ifndef __cplusplus
    printf("Test requires C++. Skipped.\n");
#else
    {
        void *ret = 0;
        Guard g("main", counter);
        pthread_t id;
        assert(0 == pthread_create(&id, 0, func, ret_value));
        assert(0 == pthread_join(id, &ret));
        assert(ret == ret_value);
    }
    assert(counter == init_counter_value);
#endif /*__cplusplus */
    return 0;
}
===================================


PS3: Changes to the 'tests/Makefile' (diff file, use patch):
===================================
--- ..\..\pthreads\tests\Makefile	Fri Oct 26 12:12:48 2001
+++ Makefile	Tue Dec 18 14:16:00 2001
@@ -41,7 +41,7 @@
 	  mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass  mutex2.pass
mutex3.pass  \
 	  condvar1.pass  condvar2.pass  condvar2_1.pass  \
 	  exit1.pass  create1.pass  equal1.pass  \
-	  exit2.pass  exit3.pass  \
+	  exit2.pass  exit3.pass exit4.pass \
 	  join0.pass  join1.pass  join2.pass  \
 	  mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass  mutex6r.pass
\
 	  count1.pass  once1.pass  tsd1.pass  \
@@ -186,6 +186,7 @@
 exit1.pass:
 exit2.pass: create1.pass
 exit3.pass: create1.pass
+exit4.pass: create1.pass
 eyal1.pass: tsd1.pass
 inherit1.pass: join1.pass
 join0.pass: create1.pass
===================================

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2001-12-20 16:46 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-01-05  8:30 pthreads VCE: problem with destructor Gardian, Milan
2001-12-18  6:18 ` Gardian, Milan
2001-01-11  6:04 Mike Kinghan
2001-12-18  7:00 ` Mike Kinghan
2001-01-11  7:04 Bossom, John
2001-01-15  7:40 ` Ross Johnson
2001-01-24 14:02   ` reentrant
2001-03-10  6:41     ` Thomas Pfaff
2001-12-20  1:25       ` Thomas Pfaff
2001-12-19 10:22     ` reentrant
2001-12-19  3:38   ` Ross Johnson
2001-12-18 12:22 ` Bossom, John
2001-01-16  1:18 Gardian, Milan
2001-12-19  4:05 ` Gardian, Milan
2001-01-16  7:38 Alexander Terekhov
2001-12-19  4:40 ` Alexander Terekhov
2001-01-16 16:48 Bossom, John
2001-12-19  6:02 ` Bossom, John
2001-01-24 21:42 Alexander Terekhov
2001-12-19 11:01 ` Alexander Terekhov
2001-02-01  6:46 Alexander Terekhov
2001-12-19 11:30 ` Alexander Terekhov
2001-02-23  8:35 Bossom, John
2001-12-19 13:19 ` Bossom, John
2001-03-12  5:53 Alexander Terekhov
2001-12-20  2:35 ` Alexander Terekhov
2001-03-22 11:19 Thomas Pfaff
2001-12-20  4:40 ` Thomas Pfaff
2001-03-22 11:39 Alexander Terekhov
2001-12-20  6:08 ` Alexander Terekhov
2001-03-22 11:41 Bossom, John
2001-12-20  8:46 ` Bossom, John

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).