This is the mail archive of the pthreads-win32@sources.redhat.com mailing list for the pthreas-win32 project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RE: problem using pthread_cancel and pthread_mutex_lock


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" <rpj@callisto.canberra.edu.au>
> To: "vc" <vcotirlea1@hotmail.com>
> Cc: <pthreads-win32@sources.redhat.com>
> 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" <vcotirlea1@hotmail.com>
> > >To: <pthreads-win32@sources.redhat.com>
> > >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 <windows.h>
> > >>#include <stdio.h>
> > >>#include <stdlib.h>
> > >>#include <pthread.h>
> > >>#include <errno.h>
> > >>
> > >>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
> > >>
> > >>
> > >>
> >
> >


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]