From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1020 invoked by alias); 19 Dec 2001 12:40:10 -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 982 invoked from network); 19 Dec 2001 12:40:05 -0000 Received: from unknown (HELO d12lmsgate-2.de.ibm.com) (195.212.91.200) by sources.redhat.com with SMTP; 19 Dec 2001 12:40:05 -0000 Received: from d12relay02.de.ibm.com (d12relay02.de.ibm.com [9.165.215.23]) by d12lmsgate-2.de.ibm.com (1.0.0) with ESMTP id NAA103214 for ; Wed, 19 Dec 2001 13:40:04 +0100 Received: from d12ml007.de.ibm.com (d12ml007_cs0 [9.165.223.36]) by d12relay02.de.ibm.com (8.11.1m3/NCO v5.01) with ESMTP id fBJCeb2107180 for ; Wed, 19 Dec 2001 13:40:37 +0100 Importance: Normal Subject: Re: pthreads VCE: problem with destructor To: pthreads-win32@sources.redhat.com X-Mailer: Lotus Notes Release 5.0.8 June 18, 2001 Message-ID: From: "Alexander Terekhov" Date: Tue, 16 Jan 2001 07:38:00 -0000 X-MIMETrack: Serialize by Router on D12ML007/12/M/IBM(Release 5.0.8 |June 18, 2001) at 19/12/2001 13:40:43 MIME-Version: 1.0 Content-type: text/plain; charset=us-ascii X-SW-Source: 2001/txt/msg00010.txt.bz2 > > 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 @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" cc: "'Gardian, Milan'" , "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: > > > 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: "Alexander Terekhov" To: pthreads-win32@sources.redhat.com Subject: Re: pthreads VCE: problem with destructor Date: Wed, 19 Dec 2001 04:40:00 -0000 Message-ID: X-SW-Source: 2001/msg00148.html Message-ID: <20011219044000.3nw_rquKRIvE9aLBF2ygCD7MfBE7NY0H1gRMY8JSjQk@z> > > 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 @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" cc: "'Gardian, Milan'" , "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: > > > 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.