From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7022 invoked by alias); 19 Dec 2001 11:38:41 -0000 Mailing-List: contact pthreads-win32-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: pthreads-win32-owner@sources.redhat.com Received: (qmail 6980 invoked from network); 19 Dec 2001 11:38:36 -0000 Received: from unknown (HELO real.ise.canberra.edu.au) (137.92.140.34) by sources.redhat.com with SMTP; 19 Dec 2001 11:38:36 -0000 Received: from ise.canberra.edu.au (IDENT:rpj@special.ise.canberra.edu.au [137.92.140.39]) by real.ise.canberra.edu.au (8.9.3/8.8.7) with ESMTP id WAA09067; Wed, 19 Dec 2001 22:38:01 +1100 Message-ID: <3C207C17.42CE925C@ise.canberra.edu.au> Date: Mon, 15 Jan 2001 07:40:00 -0000 From: Ross Johnson Reply-To: rpj@ise.canberra.edu.au Organization: University of Canberra, DMT, xISE X-Mailer: Mozilla 4.7 [en] (X11; U; Linux 2.2.12-20 i686) X-Accept-Language: en MIME-Version: 1.0 To: "Bossom, John" CC: "'Gardian, Milan'" , "Pthreads-Win32@Sources.Redhat.Com" Subject: Re: pthreads VCE: problem with destructor References: <430F887D415DD1118C2700805F31ECF106B58985@sota0005.cognos.com> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-SW-Source: 2001/txt/msg00008.txt.bz2 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: > > > 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(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. From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ross Johnson To: "Bossom, John" Cc: "'Gardian, Milan'" , "Pthreads-Win32@Sources.Redhat.Com" Subject: Re: pthreads VCE: problem with destructor Date: Wed, 19 Dec 2001 03:38:00 -0000 Message-ID: <3C207C17.42CE925C@ise.canberra.edu.au> References: <430F887D415DD1118C2700805F31ECF106B58985@sota0005.cognos.com> X-SW-Source: 2001/msg00146.html Message-ID: <20011219033800.70ZmnzbJ8T2BRtu9Gmt-MyKlqd996cFR30G73l5fU9U@z> 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: > > > 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(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.