From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 23166 invoked by alias); 9 Mar 2004 14:06:26 -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 23154 invoked from network); 9 Mar 2004 14:06:23 -0000 Received: from unknown (HELO hotmail.com) (65.54.246.19) by sources.redhat.com with SMTP; 9 Mar 2004 14:06:23 -0000 Received: from mail pickup service by hotmail.com with Microsoft SMTPSVC; Tue, 9 Mar 2004 06:06:22 -0800 Received: from 62.245.182.10 by bay2-dav47.bay2.hotmail.com with DAV; Tue, 09 Mar 2004 14:06:19 +0000 X-Originating-IP: [62.245.182.10] X-Originating-Email: [vcotirlea1@hotmail.com] X-Sender: vcotirlea1@hotmail.com From: "vc" To: Cc: References: <4047B840.5000509@callisto.canberra.edu.au> Subject: Re: problem using pthread_cancel and pthread_mutex_lock Date: Tue, 09 Mar 2004 14:06:00 -0000 MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Message-ID: X-OriginalArrivalTime: 09 Mar 2004 14:06:22.0897 (UTC) FILETIME=[B4002210:01C405DF] X-SW-Source: 2004/txt/msg00023.txt.bz2 Hi Ross, Thanks a lot for your answer. The application that I'm talking about is a Linux application that needs to be ported on Windows. The reason why this app is using the async cancelation is that if for instance a thread is doing a read() from a socket where nothing is written this read() will block indefinitelly. Because of this we have a so called "thread monitor" that is killing the threads that are not responding for a long time. In the case I explained above if I use cancel deferred this thread will never be killed as it never gets to a cancelation point. I know that a thread shouldn't hang, but this is a cpomplex application and you never know, that is why the thread monitor was implemented. I will talk to my Linux coleagues and let's see if we can come up with a solution. If not, is it ok if I just change the pthread lib as I described in my previous email? Or I could broke something? Changes that I would make: In pthread_mutex_lock calling at the begining pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); and at the end: pthread_setcanceltype(oldtype, NULL); //put back As the pthread_setcanceltype calls also pthread_mutex_lock => recursivity, I would add a param to pthread_mutex_lock so that when it is called from the pthread_setcanceltype those 2 calls are not made .... What do you say? Thanks in advance, Viv ----- Original Message ----- From: "Ross Johnson" To: "vc" Cc: Sent: Friday, March 05, 2004 12:14 AM Subject: Re: problem using pthread_cancel and pthread_mutex_lock > Hi VC, > > I saw you're original post and the response that you got advising > against async cancelation, etc, which I would urge you to consider > further, even if you need to redesign your application. > > There is another reason to avoid async cancelation that is specific to > pthreads-win32: this implementation only approximates async cancelation > because it relies on the thread actually running at some point after > cancelation. So if your thread is blocked on a resource at the time that > it's async canceled, it won't actually exit until it's unblocked in some > way to resume execution (at which point it will exit immediately) - and > if you can do that then you don't need async cancelation anyway. > Unfortunately, the time you're most likely to really need an async > cancel - to kill a thread blocked on a system resource that you can't > unblock - is the very time it won't work in pthreads-win32, and if it > did work, as in does in other implementations, then you'd probably be > creating a resource leak. So it's hard to find a good argument for async > cancel. > > If you were to list the situations where your threads could possibly > hang, then you'd probably find that there's a solution for each instance. > > Re switching cancel state within the library:- > There are places in the library that temporarily suspend cancelability > for cancel safety, usually because the standard requires it, but mutexes > are not one of them, for the simple reason that, for the vast majority > of cases, it isn't needed, while speed is, and for those rare cases that > do need it, programmers can employ solutions similar to the one you've > chosen. > > A few more suggestions: > If you're using mutexes to control access to resources that could hang > your application then maybe semaphores would be more appropriate - they > are not owned by any thread and sem_wait() is a defined [deferred] > cancelation point. There is also pthread_testcancel(), which you can use > to create your own [deferred] cancelation points. > > There are also timed versions of all of the synchronisation objects: > pthread_mutex_timedlock(), sem_timedwait(), > pthread_rwlock_timedrdlock(), pthread_rwlock_timedwrlock(), and > pthread_cond_timedwait(); that you can perhaps exploit in your attempts > to avoid canceling threads at all. > > Hope that helps. > > Regards. > Ross > > vc wrote: > > >Hi all, > > > >I found a solution to the problem I have described (see below my orig email) > >and I'm wondering if this is ok ... > > > >In my program I have to use asynchronous cancellation as I have something > >called a "thread monitor" and > >if one thread hangs I want after a while my thread monitor to kill it > >regardless of where that > >thread hanged. Using asynchronous cancellation makes problems (as I > >discovered until now) > >only when a thread is in a pthread_mutex_lock call, as in that case, by > >canceling the thread > >the mutex is in an unusable state. > > > >So what I have done is like this (see below): just before calling the > >pthread_mutex_lock > >I change the cancellation to deferred cancellation then call the > >pthread_mutex_lock and then set back > >the original cancellation mode: > > > >void reader_function (void *arg ) > >{ > > > > pthread_cleanup_push(cleanup_routine, (void *) &test_data); > > > > retval = pthread_detach (pthread_self()); > > > > pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &state); > > pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &state); > > > > retval = protect_code_with_mutex_deferred(); > > pthread_cleanup_pop(1); > > > > pthread_exit(NULL); > >} > > > >int protect_code_with_mutex_deferred(void) > >{ > > int oldtype = 0; > > > > pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); > > retval = pthread_mutex_lock(&my_mutex); > > pthread_setcanceltype(oldtype, NULL); //put back > > [...] > >} > > > >This seems to work just fine and seems to solve my problem. As I'm generaly > >using asynchronous cancellation > >my thread can be killed at any point and when a pthread_mutex_lock is done > >because I switch > >to deferred cancellation I can be sure that my thread will first go out from > >the pthread_mutex_lock > >call and then it will be canceled, so in my cleanup fction I can do an > >unlock of the mutex. > > > >But I am wondering why this way of solving the problem was not added to the > >pthread library? Am I missing something? > >Is something wrong here? Am I overseen something? > > > >If no, then in the pthread library in the pthread_mutex_lock at the > >beginning the: > > pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); could be called > >and at the end the: > > pthread_setcanceltype(oldtype, NULL); > >could be called. > >Of course some other changes are needed as pthread_setcanceltype calls also > >pthread_mutex_lock, but for internal use, I mean within the library the > >pthread_mutex_lock > >could be used with one more param, so that when pthread_mutex_lock is called > >from within the lib these > >2 lines will never be executed. > > > >Any feedback would be appreciated. > >Thanks a lot, > >Viv > > > > > >----- Original Message ----- > >From: "vc" > >To: > >Sent: Monday, February 23, 2004 6:45 PM > >Subject: problem using pthread_cancel and pthread_mutex_lock > > > > > > > > > >>Hi all, > >> > >>I am using the pthread library and I'm having a problem while using > >>pthread_cancel and pthread_mutex_lock. > >>Problem description: > >>I start 2 threads: thread1 and thread2. > >>thread1 is doing a pthread_mutex_lock(&mutex), then sleeps for 5 secs and > >>then it is doing > >>a pthread_cancel for the thread2, then is doing a > >>pthread_mutex_unlock(&mutex) > >>Thread2 is doing a pthread_mutex_lock(&mutex), where it stays as the mutex > >>is owned > >>by the thread1, and at this point the cancel is called. > >>Even if in the cleanup procedure of the thread2 I'm doing an > >>pthread_mutex_unlock or > >>not, next time when the thread1 is trying a pthread_mutex_lock(&mutex) it > >>will block > >>and never gets the mutex. > >>Also the pthread_mutex_unlock(&mutex) for the thread2 in the cleanup > >>function fails > >>(ret value is 1) > >> > >>So, my question is: how can a thread cleanly cancel another thread which > >> > >> > >is > > > > > >>waiting in a 'pthread_mutex_lock' call, so that this mutex is available > >>again ? > >> > >>Here is a sample program: > >>==================== > >> > >>#include > >>#include > >>#include > >>#include > >>#include > >> > >>void cleanup_routine(void *arg); > >>void reader_function(void *arg); > >>void monitor(void *arg); > >>int global_counter=0; > >> > >>pthread_mutex_t my_mutex; > >>int id[2]; > >>pthread_t reader[2]; > >>int cancel_mode; > >> > >> > >>int main(int argc, char *argv[]) > >>{ > >> int my_args; > >> int err = 0; > >> cancel_mode = 1; > >> > >> printf("We'll try to cancel with mode ASYNCHRONOUS\n"); > >> > >> id[0] = 1; > >> id[1] = 2; > >> pthread_mutex_init(&my_mutex, NULL); > >> > >> my_args = 1; > >> pthread_create( &reader[0], NULL, (void*)&monitor, (void *) &my_args); > >> Sleep(2000); > >> my_args = 2; > >> pthread_create( &reader[1], NULL, (void*)&reader_function, (void *) > >>&my_args); > >> > >> while(1) { > >> Sleep(1000); > >> } > >>} > >> > >>void monitor (void *arg ) > >>{ > >> int retval; > >> > >> printf("Monitor: Entering monitor routine\n\n"); > >> > >> printf("Monitor: monitor is locking thread...\n"); > >> pthread_mutex_lock(&my_mutex); > >> printf("Monitor: monitor is locking thread - okay\n"); > >> Sleep (5000); > >> > >> printf("Monitor: monitor kills pthread 0x%x:\n", (unsigned int) > >>reader[1]); > >> retval = pthread_cancel (reader[1]); > >> printf("Monitor: kill returns %d\n", retval); > >> > >> printf("Monitor: monitor is unlocking thread...\n"); > >> pthread_mutex_unlock(&my_mutex); > >> printf("Monitor: monitor is unlocking thread - okay\n"); > >> > >> printf("Monitor: monitor running\n"); > >> Sleep (3000); > >> printf("Monitor: monitor is locking thread...\n"); > >> pthread_mutex_lock(&my_mutex); // HERE: it will never get the lock! It > >>will hang here! > >> printf("Monitor: monitor is locking thread - okay\n"); > >> > >> Sleep(1000); > >> printf("Monitor: monitor is unlocking thread...\n"); > >> pthread_mutex_unlock(&my_mutex); > >> printf("Monitor: monitor is unlocking thread - okay\n"); > >>} > >> > >> > >>int args; > >> > >>void reader_function (void *arg ) > >>{ > >> int i=0; > >> int id, state; > >> int retval; > >> > >> pthread_cleanup_push(cleanup_routine, NULL); > >> retval = pthread_detach (pthread_self()); > >> > >> pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &state); > >> printf("Thread: pthread_setcancelstate: old state was %d\n", state); > >> > >> if (cancel_mode == 1) { > >> pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &state); > >> } > >> > >> id = *(int *) arg; > >> printf("Thread: entered thread %d\n", id); > >> printf("Thread: thread returns: 0x%x\n", (unsigned int) > >> > >> > >pthread_self()); > > > > > >> printf("Thread: testthread is locking thread...\n"); > >> pthread_mutex_lock(&my_mutex); > >> printf("Thread: testthread is locking thread - okay\n"); > >> > >> // HERE: it shouldn't come here as the thread will be canceled by the > >>monitor thread > >> printf("Thread: testthread is unlocking thread...\n"); > >> pthread_mutex_unlock(&my_mutex); > >> printf("Thread: testthread is unlocking thread - okay\n"); > >> > >> printf("Thread: reader_function finished\n"); > >> > >> pthread_cleanup_pop(0); > >>} > >> > >> > >>void cleanup_routine(void *arg) > >>{ > >> int ret = 0; > >> printf("ThreadCleanup: cleanup called\n"); > >> Sleep(5000); > >> > >> ret = pthread_mutex_unlock(&my_mutex); > >> printf("ThreadCleanup:Cleanup routine unlock ret = %d\n", ret); > >> printf("ThreadCleanup:waitThread_cleanup done\n"); > >>} > >> > >> > >>The output looks like: > >>================= > >>We'll try to cancel with mode ASYNCHRONOUS > >>Monitor: Entering monitor routine > >> > >>Monitor: monitor is locking thread... > >>Monitor: monitor is locking thread - okay > >>Thread: pthread_setcancelstate: old state was 0 > >>Thread: entered thread 2 > >>Thread: thread returns: 0x312d80 > >>Thread: testthread is locking thread... > >>Monitor: monitor kills pthread 0x312d80: > >>Monitor: kill returns 0 > >>Monitor: monitor is unlocking thread... > >>ThreadCleanup: cleanup called > >>Monitor: monitor is unlocking thread - okay > >>Monitor: monitor running > >>Monitor: monitor is locking thread... > >>ThreadCleanup:Cleanup routine unlock ret = 1 > >>ThreadCleanup:waitThread_cleanup done > >> > >> > >>So, from the output can be seen that the 1st thread (called monitor) will > >>never be able > >>to gain the mutex again. > >> > >>Sorry for the long post, > >>Any help will be appreciated, > >>Thanks a lot, > >>Viv > >> > >> > >> > >