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 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]