Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why can't I cancel pthreads while waiting on a condition, multiple times?

In my program, pthreads are spawned and wait for conditions, and may be cancelled while waiting. This works for a while but then stops working - the thread cannot acquire the mutex anymore.

Below is the SSCCE. The routine code follows well-known canonical examples for pthread_cond_wait, except I don't need to check while (condition not true) before waiting, because the condition is never signaled (if I do check, the same problem appears).

For clarity, I am not including checking returns of system calls, but they are all successful.

#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t global_lock;
pthread_cond_t global_cond;

void *routine(void *arg) {
    pthread_mutex_lock(&global_lock);
    printf("waiting...\n");

    /*the condition will never arrive*/
    pthread_cond_wait(&global_cond, &global_lock);
    pthread_mutex_unlock(&global_lock);
    return NULL;
}

int main() {
    pthread_t thread;

    pthread_cond_init(&global_cond, NULL);
    pthread_mutex_init(&global_lock, NULL);

    while (1) {
        pthread_create(&thread, NULL, routine, NULL);

        /*
        ** give thread enough time to start waiting
        ** should perhaps have thread signal us it started waiting
        ** but this is good enough for this example
        */
        sleep(1);

        pthread_cancel(thread);
    }

    return 0;
}

I would expect this would print waiting... every second. But it does not, it just prints it twice and that is it, third time, routine is not able to initially acquire the mutex. Why??

like image 848
Mark Galeck Avatar asked Oct 24 '25 12:10

Mark Galeck


1 Answers

After somethinking, I was able to fix the problem using EOF's comment. If EOF wants to post an answer by himself, or copy and paste parts or whole of my answer, I will accept his answer.

The problem with my code is that it does not establish a "cleanup handler" for the cancellation point at pthread_cond_wait. The corrected code for routine is as follows, and now it works as expected.

void cleanup_handler(void *plock) {
    pthread_mutex_unlock(plock);
}

void *routine(void *arg) {
    pthread_cleanup_push(cleanup_handler, &global_lock);

    pthread_mutex_lock(&global_lock);
    printf("waiting...\n");

    /*the condition will never arrive*/
    pthread_cond_wait(&global_cond, &global_lock);
    pthread_mutex_unlock(&global_lock);

    pthread_cleanup_pop(0);
    return NULL;
}
like image 172
Mark Galeck Avatar answered Oct 26 '25 07:10

Mark Galeck



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!