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