From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15644 invoked by alias); 9 Mar 2004 23:25: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 15564 invoked from network); 9 Mar 2004 23:25:06 -0000 Received: from unknown (HELO ns1.daronmont.com.au) (150.101.16.97) by sources.redhat.com with SMTP; 9 Mar 2004 23:25:06 -0000 Received: from pd001649.daronmont.com.au by ns1.daronmont.com.au via smtpd (for sources.redhat.com [67.72.78.213]) with SMTP; 9 Mar 2004 23:25:19 UT Received: by mail.daronmont.com.au with Internet Mail Service (5.5.2653.19) id ; Wed, 10 Mar 2004 09:55:04 +1030 Message-ID: <8179ED123ECCD611A5490000F822E6EA49BEF0@mail.daronmont.com.au> From: Simon Gerblich To: vc Cc: pthreads-win32@sources.redhat.com Subject: RE: problem using pthread_cancel and pthread_mutex_lock Date: Tue, 09 Mar 2004 23:25:00 -0000 MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" X-SW-Source: 2004/txt/msg00027.txt.bz2 Hi Viv, I'm also writing code that we compile with redhat linux and pthreads-win32. I get around your socket problem by having a tcp network class that does the read(), write() calls etc. recv() will return with an error if you call shutdown() and close()/closesocket() on the socket. I have a call to shutdown() and close()/closesocket() in the destructor of the class. It works well for us. Maybe you could call shutdown() and close()/closesocket() instead of "killing the thread", and the recv() call will return and the thread can shutdown cleanly. Simon > -----Original Message----- > From: vc [SMTP:vcotirlea1@hotmail.com] > Sent: Wednesday, March 10, 2004 12:38 AM > To: rpj@callisto.canberra.edu.au > Cc: pthreads-win32@sources.redhat.com > Subject: Re: problem using pthread_cancel and pthread_mutex_lock > > 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 > > >> > > >> > > >> > > > >