This is the mail archive of the
pthreads-win32@sources.redhat.com
mailing list for the pthreas-win32 project.
Re: problem using pthread_cancel and pthread_mutex_lock
- From: "vc" <vcotirlea1 at hotmail dot com>
- To: <pthreads-win32 at sources dot redhat dot com>
- Date: Mon, 1 Mar 2004 17:29:10 +0100
- Subject: Re: problem using pthread_cancel and pthread_mutex_lock
- References: <BAY2-DAV45e2Qw4hVJb0003de2c@hotmail.com>
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
>