From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14954 invoked by alias); 8 Jan 2007 14:31:51 -0000 Received: (qmail 14880 invoked by uid 22791); 8 Jan 2007 14:31:50 -0000 X-Spam-Check-By: sourceware.org Received: from cv3.cv.nrao.edu (HELO cv3.cv.nrao.edu) (192.33.115.2) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 08 Jan 2007 14:31:44 +0000 Received: from [127.0.0.1] (rpm.ad.nrao.edu [10.12.96.162]) by cv3.cv.nrao.edu (8.13.1/8.13.1/cv-ws-8.12) with ESMTP id l08EVMjm017521; Mon, 8 Jan 2007 09:31:24 -0500 Message-ID: <45A255BA.8040206@nrao.edu> Date: Mon, 08 Jan 2007 14:31:00 -0000 From: Morgan McLeod User-Agent: Thunderbird 1.5.0.7 (Windows/20060909) MIME-Version: 1.0 To: Ross Johnson CC: Pthreads-Win32 list Subject: Re: semaphores and handle leaks References: <456C62A1.9090202@marcelruff.info> <456C63DC.4010008@marcelruff.info> <456D6AEC.8070804@marcelruff.info> <4575E103.8080105@nrao.edu> <4575FCC4.5020707@nrao.edu> <45A05B33.50509@homemail.com.au> In-Reply-To: <45A05B33.50509@homemail.com.au> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-MailScanner-Information: Please contact postmaster@cv.nrao.edu for more information X-MailScanner: Found to be clean X-MailScanner-SpamCheck: not spam, SpamAssassin (not cached, score=-101.44, required 5, autolearn=disabled, ALL_TRUSTED -1.44, USER_IN_WHITELIST -100.00) X-IsSubscribed: yes Mailing-List: contact pthreads-win32-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: pthreads-win32-owner@sourceware.org X-SW-Source: 2007/txt/msg00006.txt.bz2 Hello Ross, all: Yes 2.8.0 seems to fix the handle leaks that I was seeing. I haven't tried the workaround you suggest. I have attached the latest version of my test program below, including updated comments indicating handle counts. Thanks -MM Ross Johnson wrote: > Hi Morgan, > > Could you try your sample code below with version 2.8.0 of the > library. I believe the leak has been plugged. Sergey Fokin reported a > race in sem_destroy() that, in your code below, may result in > semaphores not being destroyed. > > Where you init and destroy semaphores in thread1 ... > > sem_init(E.synchLock, 0, 0); > ... > sem_destroy(E.synchLock); > > ... if you were to check the return value from sem_destroy() I believe > you would find that errno sometimes returns EBUSY. This bug has been > fixed in 2.8.0. > > For prior versions of the library, the following modification should > provide a workaround (untested):- > > while (sem_destroy(E.synchLock) != 0 && errno == EBUSY) > { > // Assuming can busy-wait on SMP systems - in pthreads-win32 this > looks at the number of processors > // assigned to the process, which may be <= number in system. Not > portable. > if (pthread_num_processors_np() < 2) > sched_yield(); > } > > Regards. > Ross #include #include #include #include struct listElem { int num; sem_t *synchLock; listElem(int _num = 0, sem_t *_synchLock = NULL) : num(_num), synchLock(_synchLock) {} ~listElem() {} }; const bool JOIN_THREADS = false; const int COUNT = 1000; listElem list1[COUNT]; listElem list2[COUNT]; int pos1, pos2, end1, end2; // mutexes to protect the lists: pthread_mutex_t mutex1; pthread_mutex_t mutex2; // flags to tell the threads to stop: bool shutdownNow; bool shutdownDone1; bool shutdownDone2; // thread 1 processes list1: void *thread1(void *arg) { listElem E; while (true) { if (shutdownNow) { shutdownDone1 = true; pthread_exit(NULL); } pthread_mutex_lock(&mutex1); if (end1 == pos1) pthread_mutex_unlock(&mutex1); else { // get the next element from the list: E = list1[pos1++]; pthread_mutex_unlock(&mutex1); // save the original semaphore: sem_t *sem1 = E.synchLock; // create and initialize a new semaphore. // substitute it for the original: sem_t sem2; E.synchLock = &sem2; sem_init(E.synchLock, 0, 0); // put the item in list2 for processing by thread2: pthread_mutex_lock(&mutex2); list2[end2++] = E; pthread_mutex_unlock(&mutex2); // Wait on, then destroy the substitute semaphore: sem_wait(E.synchLock); sem_destroy(E.synchLock); // put back and post on the original semaphore: E.synchLock = sem1; sem_post(E.synchLock); printf("thread1: %d done\n", E.num); } Sleep(10); } } // thread2 processes list2: void *thread2(void *arg) { listElem E; while (true) { if (shutdownNow) { shutdownDone2 = true; pthread_exit(NULL); } pthread_mutex_lock(&mutex2); if (end2 == pos2) pthread_mutex_unlock(&mutex2); else { E = list2[pos2++]; pthread_mutex_unlock(&mutex2); sem_post(E.synchLock); printf("thread2: %d done\n", E.num); } Sleep(10); } } int main(int, char*[]) { // Initialize flags and indexes: shutdownNow = shutdownDone1 = shutdownDone2 = false; pos1 = pos2 = end1 = end2; pthread_mutex_init(&mutex1, NULL); pthread_mutex_init(&mutex2, NULL); // Pause to look at Task Manager. Handles = 10: Sleep(5000); sem_t synchLocks[COUNT]; for (int index = 0; index < COUNT; ++index) { sem_init(&synchLocks[index], 0, 0); listElem E(index, &synchLocks[index]); list1[end1++] = E; } // Handles is between 2015 and 2019. // With pthreads_win32 ver. 2.7.0 it would start to leak handles... pthread_t T1; pthread_create(&T1, NULL, thread1, NULL); pthread_t T2; pthread_create(&T2, NULL, thread2, NULL); if (!JOIN_THREADS) { pthread_detach(T1); pthread_detach(T2); } while (end1 > pos1 || end2 > pos2) Sleep(10); // Pause to look at Task Manager: // With 2.7.0 Handles = 2151 with joinable threads (varies) // Handles = 2265 with detached threads (varies) // With 2.8.0 Handles holds between 2015 and 2019. Sleep(5000); shutdownNow = true; void *tr; if (JOIN_THREADS) { pthread_join(T1, &tr); pthread_join(T2, &tr); } while (!shutdownDone1 && !shutdownDone2) Sleep(10); for (int index = 0; index < COUNT; ++index) sem_destroy(&synchLocks[index]); pthread_mutex_destroy(&mutex1); pthread_mutex_destroy(&mutex2); // Pause to look at Task Manager: // With 2.7.0 Handles = 148 with joinable threads (varies) // Handles = 268 with detached threads (varies) // With 2.8.0 Handles = 9 or 12. Sleep(5000); printf("done\n"); return 0; }