Tuesday, September 25, 2018

Pthraed - Use of pthread_exit

pthread_exit - terminate calling thread
void pthread_exit(void *retval)

Terminate the calling thread and return a value via retval. The return value is used by pthread_join. It also calls clean-up handlers and destructors for thread-specific data to do the cleanup activity.

Pthread_exit is implicitly called when a thread returns from its start function. If the application functionality needs, it can also be called explicitly to exit from a function other than start function.

A simple example



In this example using different global variables to return from the thread and to access it in the main thread using pthread_join(3). This shows the copying of data from pthread_exit(3) to pthread_join(3).
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <errno.h> void *functionC(void *); int *retVal; int *ret; int main() { int rc; pthread_t th; ret = (int *) malloc(sizeof(int)); *ret = 5; if(rc = pthread_create(&th, NULL, &functionC, NULL)) { printf("Thread creation failed, return code %d, errno %d", rc, errno); } pthread_join(th, (void**)&ret); printf("Return value from thread = %d\n", *ret); return 0; } void *functionC(void *) { retVal = (int *) malloc(sizeof(int)); *retVal = 1; printf("Checking pthread_exit\n"); return (void*) retVal; } // Output of the above code Checking pthread_exit Return value from thread = 1



Using pthread_exit in main


When pthread_exit is used in the main thread as a replacement for exit (), will keep the main thread in zombie(defunct) status until all other threads exit. It will allow other threads to continue running. Since main thread exits after pthread_exit, it’s not possible to check the return status of threads and do clean-up after a pthread_exit call() as main thread exits. This is not a replacement for pthread_join. It should not be used as a single command to wait for all the threads.

    #include <stdlib.h>
    #include <pthread.h>
    #include <unistd.h>
    #include <errno.h>

    void *functionC(void *);

    int main()
    {
            int rc;
            pthread_t th;

            if(rc = pthread_create(&th, NULL, &functionC, NULL))
            {
                    printf("Thread creation failed, return code %d, errno %d", rc, errno);
            }

            printf("Main thread %lu: Sleeping for 20 seconds\n", pthread_self());
            fflush(stdout);
            sleep(20);
            pthread_exit(NULL);
            printf("Main thread %lu: This will not be printed\n", pthread_self());
            exit(0);
    }

    void *functionC(void *)
    {
            printf("Thread %lu: Sleeping for 20 second\n", pthread_self());
            sleep(20);
            printf("Thread %lu: Came out of first and sleeping again\n", pthread_self());
            sleep(20);
            printf("CThread %lu: Came out of second sleep\n", pthread_self());
    }
    // Output of the above code
    Main thread 140166909204288: Sleeping for 20 seconds
    Thread 140166900684544: Sleeping for 20 second
    Thread 140166900684544: Came out of first and sleeping again
    CThread 140166900684544: Came out of second sleep
    // ps output
    root@xxxx-VirtualBox:~/pthread_tst# ps -elfT |grep a.out
    0 S root      9530  9530  9496  0  80   0 -  3722 hrtime 17:31 pts/1    00:00:00 ./a.out
    1 S root      9530  9531  9496  0  80   0 -  3722 hrtime 17:31 pts/1    00:00:00 ./a.out
    0 S root      9537  9537  2182  0  80   0 -  5384 pipe_w 17:31 pts/0    00:00:00 grep --color=auto a.out
    root@xxxx-VirtualBox:~/pthread_tst# ps -elfT |grep a.out
    0 Z root      9530  9530  9496  0  80   0 -     0 -      17:31 pts/1    00:00:00 [a.out] <defunct>
    1 S root      9530  9531  9496  0  80   0 -  4258 hrtime 17:31 pts/1    00:00:00 ./a.out
    0 S root      9539  9539  2182  0  80   0 -  5384 pipe_w 17:31 pts/0    00:00:00 grep     --color=auto a.out



Using exit in thread


Calling exit in any thread will terminate the process. All threads are terminated irrespective of which thread calls exit routine. A similar effect is when a signal is received which has the default action to terminate a process. In that case, all threads terminate, irrespective of which thread received signal.

    #include <stdlib.h>
    #include <pthread.h>
    #include <unistd.h>
    #include <errno.h>
    void *functionC(void *);

    int main()
    {
        int rc;
        pthread_t th;

        if(rc = pthread_create(&th, NULL, &functionC, NULL))
        {
                printf("Thread creation failed, return code %d, errno %d", rc, errno);
        }

        printf("Main thread %lu: Sleeping for 20 seconds\n", pthread_self());
        sleep(20);
        printf("Main thread %lu: Came out of sleep, join thread\n", pthread_self());
        pthread_join(th, NULL);
        printf("Main thread %lu: Thread joined\n", pthread_self());
        return 0;
    }
    void *functionC(void *)
    {
        printf("Thread %lu: Sleep for 10 seconds\n", pthread_self());
        sleep(10);
        printf("Thread %lu: Exiting from functionC\n", pthread_self());
        exit(0);
    }
    // Output of the above code: Second printf in main thread is not seen
    // as process exits after call to exit(3).
    Main thread 139865285744448: Sleeping for 20 seconds
    Thread 139865277224704: Sleep for 10 seconds
    Thread 139865277224704: Exiting from functionC

Note on pthread_exit():
  • The function has no return value and it always succeeds.
  • Process shared resources like mutexes, condition variables are not released after calling pthread_exit. They are released when a process exits. 
  • If you don't want to use the exit status of the thread and the function return type is not void *, some compiler may not give an error. However, when the thread returns from start function, pthread_exit will still copy return status to some address. It may cause a bug difficult to identify.