csavvy
csavvy

Reputation: 821

How collect thread exit status(using join) when cancelled

I am trying to cancel thread from caller or calle, but both are crashing the program

But if I join I am getting the exit status correct.

how to collect the exit status properly on pthread_cancel

man page says below

After a canceled thread has terminated, a join with that thread using pthread_join(3) obtains PTHREAD_CANCELED as the thread's exit status. (Joining with a thread is the only way to know that cancellation has completed.)

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

void *thread_func(void *arg);
int errNum = 3;
int main()
{
    pthread_t t_id;
    void *status;

    // on success pthread_create return zero
    if(pthread_create(&t_id,NULL,thread_func,NULL) != 0){
        printf("thread creation failed\n");
        return 0;   
    }

    printf("thread created with id %u successfully\n",t_id);
    // status will be collecting the pthread_exit value
    // error numberis returned incase of error

//  pthread_cancel(t_id);

    if(pthread_join(t_id,&status) != 0){
        printf("join failed\n");

    }
    printf("thread %u exited with code %d\n", t_id, *(int *)status);
    return 0;
}

void *thread_func(void *arg)
{

    printf("Inside thread_func :%u\n",pthread_self());
    //the arguments of pthread_exit should not be from local space, as it will be collected in caller using join
    //pthread_exit(&errNum);

    // if we return it may cause seg fault as we are trying to print the value from ptr(status)
    //return ;  
    pthread_cancel(pthread_self());
}

Upvotes: 0

Views: 886

Answers (1)

John Bollinger
John Bollinger

Reputation: 180306

If a thread is cancelled (before it has terminated normally), then when you join it, you will receive PTHREAD_CANCELED as the thread's return value / exit status. That macro expands to the actual void * value that is returned, so you can compare the value you receive directly to that to judge whether the thread was cancelled. It generally is not a valid pointer, so you must not try to dereference it.

Example:

    void *status;

    // ...

    if (pthread_join(t_id, &status) != 0) {
        // pthread_join failed
    } else if (status == PTHREAD_CANCELED) {
        // successfully joined a thread that was cancelled
        // 'status' MUST NOT be dereferenced
    } else {
        // successfully joined a thread that terminated normally
        // whether 'status' may be dereferenced or how else it may be
        // used depends on the thread
    }

It is worth noting that the wording of the Linux manual page is a bit fast and loose. Threads do not have an "exit status" in the sense that processes do, and the actual POSIX specifications do not use the term in the context of threads. For example, the POSIX specifications for pthread_join() say:

On return from a successful pthread_join() call with a non-NULL value_ptr argument, the value passed to pthread_exit() by the terminating thread shall be made available in the location referenced by value_ptr.

That's a bit of a mouthful compared to the Linux wording, but it is chosen to be very precise.

Note also that the choice of type void * here is intentional and useful. It is not merely an obtuse way to package an int. Through such a pointer, a thread can provide access to an object of any type, as may be useful for communicating information about the outcome of its computations. On the other hand, it is fairly common for threads to eschew that possibility and just return NULL. But if a thread did want to provide an integer code that way, then it would most likely provide an intvalue cast to type void *, rather than a pointer to an object of type int containing the chosen value. In that case, one would obtain the value by casting back to int, not by dereferencing the pointer.

Upvotes: 2

Related Questions