From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18927 invoked by alias); 18 Dec 2001 14:18:40 -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 18758 invoked from network); 18 Dec 2001 14:17:23 -0000 Received: from unknown (HELO mail.ip.tesion.net) (195.226.96.131) by sources.redhat.com with SMTP; 18 Dec 2001 14:17:23 -0000 Received: (qmail 17423 invoked from network); 18 Dec 2001 14:17:21 -0000 Received: from mail.leibinger.com (195.226.109.19) by mail.ip.tesion.net with SMTP; 18 Dec 2001 14:17:21 -0000 Received: from exchange ([192.168.17.1]) by mail.leibinger.com (Netscape Messaging Server 3.56) with ESMTP id 559; Tue, 18 Dec 2001 15:17:33 +0100 Received: by exchange with Internet Mail Service (5.5.2650.21) id ; Tue, 18 Dec 2001 15:17:15 +0100 Message-ID: <4052AC502903D411AD1200508B2C0C100314752D@exchange> From: "Gardian, Milan" To: "Pthreads-Win32@Sources.Redhat.Com" Cc: "Ross Johnson (E-mail)" Subject: pthreads VCE: problem with destructor Date: Fri, 05 Jan 2001 08:30:00 -0000 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2650.21) Content-Type: text/plain; charset="iso-8859-2" X-SW-Source: 2001/txt/msg00005.txt.bz2 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 =================================== From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Gardian, Milan" To: "Pthreads-Win32@Sources.Redhat.Com" Cc: "Ross Johnson (E-mail)" Subject: pthreads VCE: problem with destructor Date: Tue, 18 Dec 2001 06:18:00 -0000 Message-ID: <4052AC502903D411AD1200508B2C0C100314752D@exchange> X-SW-Source: 2001/msg00143.html Message-ID: <20011218061800.hxMNV2_eNve_ICR9jwDTTzCbrI6z5BnrER8TkFB7Up0@z> 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 ===================================