Notes for pthread_cancel function

/**************************************************
The correlation function:
     #include <pthread.h>
     int pthread_cancel(pthread_t thread)
                     Successful return 0, failure return error code
**************************************************/

This function is provided by POSIX to cancel other threads in the same process.
Several cancel requests are sent without waiting for the process to be cancelled to exit! Threads can
 Choose to ignore or choose other actions!

It should be noted that:
When we call it to cancel an already acquired mutex/anonymous semaphore/write lock...
If the thread that has not released its acquired lock is cancelled, then all of you want to
 Threads that want to perform tasks at this time will be asleep until the lock is released.
To avoid this problem, we can call a set of functions:
/**************************************************
    #include <pthread.h>

    void pthread_cleanup_push(void (*routine)(void *), void *arg)
    void pthread_cleanup_pop(int execute)
        Parametric interpretation: routine is a function pointer and arg is a parameter passed to routine
        When execute is zero, the registered function is deleted from the stack and will be deleted again.
        Not executed.
**************************************************/
These two functions are called thread cleanup handlers, similar to atexit functions, and we
 Multiple cleanup functions can be registered, and when the following actions are performed, the functions we register will be
 Callback (reverse order of execution and registration):
    1. When a thread exits from the pthread_exit(void *) function.
    2. When the thread responds to the cancellation request.
    3. Execute the pthread_cleanup_pop function when the execute parameter is non-zero.

These two thread cleanup handlers must appear in pairs and must be in the same scope.
Otherwise, compilation errors will occur.
Example:
    //How to use these functions to deal with the above problems!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <signal.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <pthread.h>

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

void *count(void *arg)
{
    int i=1;
    while(1)
    {
        sleep(1);
        printf("sec: %d\n", i++);
    }
}

void handler(void *arg)
{
    printf("[%u] is cancelled.\n", (unsigned)pthread_self());
    pthread_mutex_t *pm = (pthread_mutex_t *)arg;

    pthread_mutex_unlock(pm);
}

void *routine(void *arg)
{
    #ifdef CLEANUP
    pthread_cleanup_push(handler, (void *)&m);
    #endif

    pthread_mutex_lock(&m);
    printf("[%u] lock the mutex!\n", (unsigned)pthread_self());

    /*
    ** During sleep(), if the calling thread received a cancel-
    ** request and HASN'T established any cleanup handlers to
    ** unlock the mutex, it will leave the mutex a DEAD-LOCK
    ** state.
    */
    sleep(2);
    printf("[%u]: job finished!\n", (unsigned)pthread_self());


    pthread_mutex_unlock(&m);
    printf("[%u] unlock the mutex!\n", (unsigned)pthread_self());

    /*
    ** NOTE: 
    **
    ** pthread_cleanup_push() and pthread_cleanup_pop() may be
    ** implemented as macro that expand to text containing '{'
    ** and '}', respectively. For this reason, the caller must
    ** user them pairly and ensure that they are paired within
    ** a same function and at the same lexical nesting level.
    */
    #ifdef CLEANUP
    pthread_cleanup_pop(0);
    #endif


    pthread_exit(NULL);
}

int main(int argc, char **argv)
{
    pthread_t t, t1, t2;
    pthread_create(&t, NULL, count, NULL);


    pthread_create(&t1, NULL, routine, NULL);
    pthread_create(&t2, NULL, routine, NULL);
    printf("[%u] ==> t1\n", (unsigned)t1);
    printf("[%u] ==> t2\n", (unsigned)t2);
    printf("[%u] ==> main\n", (unsigned)pthread_self());

    sleep(1);
    pthread_cancel(t1);
    pthread_cancel(t2);

    sleep(2);

    pthread_mutex_lock(&m);
    printf("[%u] locked the mutex!\n",
        (unsigned)pthread_self());
    pthread_mutex_unlock(&m);

    exit(0);
}

Posted by nec9716 on Fri, 07 Jun 2019 14:48:45 -0700