Basics Of Thread Programming – Part 3

                                               Introduction to POSIX Thread Programming


POSIX is a standard that defines the standards for operating systems to guarantee portability of code across different operating systems. As a part of it, standards are defined for thread support, implementation etc. The standard defines C language based API for programming threads with data structures, functions etc. Most of the UNIX variants and Linux operating systems support this POSIX threading standard. All these operating systems implement the POSIX defined API for programming threads. Also the behavior of APIs and threads will be same irrespective of these operating systems. Again all of these operating systems may provide their own additional flavor of threading libraries which may or may not be compliant with POSIX standard, examples are Solaris Threads, Linux Threads etc.  But in this tutorial where ever "POSIX Threads" is used, it mean any threading library, which is compliant with POSIX threading standard.

POSIX threads can be programmed simply in C or C++ language using any standard C or C++ compiler.  Other languages may have the wrappers for the standard C language based threads or they may be implemented in proprietary way.  POSIX threads when programmed in C, will use structures, functions and some other constants defined in pthread.h and  sys/types.h header files. While compiling and linking code that uses POSIX threads, options may have to be defined to use pthread library which is the implementation library  for POSIX threads. In Cygwin(unix like environment on Windows) no such options are required. In Linux "-d_REENTRANT" and "–lpthread"  options are required for compiling and linking the code. It changes from operating system to operating system.  For such details please refer to operating system’s documentation.  Each of the following section will list a code snippet of the program to illustrate a particular feature of POSIX threads and at the last all the programs are listed completely explaining them.  

Here are the main features of POSIX threads.

Following sections explain different concepts of thread life cycle management and related APIs for programming the threads. While explaining the concept only part of the program/code  relevant to the context is shown. Please look at the complete source code available on the web site for the forking samples demonstrating the concepts explained here . There may be minor differences between the partial code snippets and the complete code listing and it is to make the illustration more effective.

Thread Creation/Starting

           
Creation of POSIX threads is to be done with pthread_create() function. It will create the thread and start the thread immediately. Following is the prototype of  pthread_create() function.

int pthread_create(pthread_t *threadID, const pthread_attr_t *threadAttributes, void*(*threadFunction)(void *), void *argumentToThreadFunction);

First parameter is a pointer to the pthread_t to return back the identity or id of the new thread created. Using that information, further operations will be done on the thread. Next parameter of type pthread_attr_t is to specify the policy of the thread functioning like priority etc. To go with the default policy pass null to it. Next parameter  is a pointer to the function, which will be executed by the thread over it’s lifetime. Thread function takes void* as parameter whose value is provided as the next argument after the function pointer. pthread_create() returns zero on success and non-zero value on failure.

On execution of  pthread_create() function a new thread will be created and the new starts it’s execution immediately by default. The thread which created the new thread will also continue it’s execution. But if the main thread exits the main() function, of  the process dies along with  the newly created thread is killed. See the following code snippet for details.
            …………………
            void *printNameOnThread(void *name){
                        /* print my name many times to the console */
            …………………………
            }
            int main() {
                        …………………….
                        pthread_t threadID;
                        /* create my thread and return from main */
                        pthread_create (&threadID, NULL, printNameOnThread, (void*)threadName);
                        /* process terminates here, so the new thread is forced to terminate       */
            }


In the above code , in main() function the default thread creates a new thread (which starts executing printNameOnThread() method), but it returns  from main. This causes the new thread to terminate. If the code is written in the following way then the thread will get a chance to run for some more time, because the main thread remains in main() for some more time.
            …………………
            int main() {
                        …………………….
                        pthread_t threadID;
                        /* create my thread */
                        pthread_create (&threadID, NULL, printNameOnThread, (void*)threadName);
                        /*  do something here , the new thread will survive and run as long as the current thread
                              doesn’t return from main() */
                        ……………………………………                                                                            
            }

Look for Create.c to find a complete working sample using this function.

Wait for the Thread to complete its execution


Newly created thread's execution will be stopped when the default thread forces the termination of the process. But there is a way for any thread to wait for completion of any other thread. This done by pthread_join() method. This method will make the thread which invoked the function to wait for the other thread to complete its execution. This is a blocking function where the function will return only after the other thread terminates. It’s prototype is as following.

int pthread_join(thread_t tid, void **status);


First parameter is to identify the thread for termination of which, the current thread will wait. Next parameter will return the status of the thread after it completes. It can be null if not interested to retrieve the status. As usual this returns zero on success and non-zero value on failure. Following is the code snippet that uses this.
            …………………
            void *printNameOnThread(void *name){
                        /* print my name many times to the console */
                        …………………………
            }
            int main() {
                        …………………….
                        pthread_t threadID;
                        /* create my thread and return from main */
                        pthread_create (&threadID, NULL, printNameOnThread, (void*)threadName);
                        //call join here so that the current/default thread will wait till the thread identified by threadID completes it’s execution
                        pthread_join(threadID, NULL);
                        //following statements will be executed by current/default thread after threadID terminates
                        …………………………….
            }

Look for Join.c to find a complete working sample using this function.

Thread Identity, Current Thread and Comparing Threads


Thread is identified by the structure pthread_t defined in  sys/types.h. A pointer to this structure is passed to pthread_create() method to get the identification information of the thread. This information is to be used where ever the thread operations are done to inform on which thread the operations are to be done. For example to wait for completion of a thread, pthread_t instance corresponding to that thread should be provided as the parameter. Following is an example.
            ………………………
            int main() {
                        …………………….
                        pthread_t threadID;
                        /* create my thread and set its information to threadID  variable */
                        pthread_create (&threadID, NULL, printNameOnThread, (void*)threadName);
                        //to join the thread just created , use threadID to tell to wait for that thread
                        pthread_join(threadID, NULL);
                        …………………………….
            }


To get the identification information of the current  thread POSIX has a function pthread_self() which returns pthread_t instance with the information of the thread (invoking the method) filled in it. In other words, pthread_self() returns  the  pthread_t instance with the information of the thread that invoked the pthread_self() function.  Following code snippet illustrates how to use the function.

Threads can be compared for equality using the pthread_equal() function.  It takes as parameters two  pthread_t instances corresponding to the threads which are to be compared. If they both correspond to the same thread  then it returns a non-zero value, and if they are representing different threads, then it returns zero. Following is an illustration.
            ……………………………………
            /* get the thread info of the current thread */
            pthread_t threadID1 = pthread_self();
            /* get again the thread info of the current thread into another variable */
            pthread_t threadID2 = pthread_self();
            /* compare the info and they should be equal because threadID1 and threadID2 correspond to same thread */
            if(pthread_equal(threadID1, threadID2))
            printf("\nBoth the threads are equal");
            ………………………………………………..

Look for SelfEqual.c to find a complete working sample using these methods.

Initialization for the Thread


For initialization of Threads POSIX has defined some flags and functions to do it safely. POSIX  will allow to do the initialization only once if the user wants it that way. Even by mistake if initialization is requested again, initialization wont be done. pthread_once_t is a structure that keeps tracks of the number of times the initialization function is invoked. If it is set to the constant PTHREAD_ONCE_INIT then it is guaranteed that the first call to pthread_once() function will execute and all the next calls will be discarded. pthread_once() function will take the initialization function as one parameter and the other parameter is pthread_once_t instance. pthread_once() function for the first time will call initialization function which does the required initialization. Following is an illustration.
……………………….
/* initialize it to ensure that initialization function will be called only once */
pthread_once_t once_status = PTHREAD_ONCE_INIT;
/* this call to do the initialization and initializeForThreading  function will be executed successfully */
pthread_once(&once_status, initializeForThreading);
………………………..
/* calling it again, so initializeForThreading function wont be invoked because it is already invoked once*/
pthread_once(&once_status, initializeForThreading);
……………………….
.
Look for SelfEqual.c to find a complete working sample using them.

Sleep the Thread


Threads can be made to sleep with sleep() function of POSIX operating systems. It is a more generic function that can be used anywhere even without POSIX threads in context. Time interval for which the execution of the current thread  should be delayed can  be given in seconds, minutes, hours and days. After sleeping for the requested amount of time, threads will wake up automatically to execute the next instruction after sleep() function call.

Wakeup the Thread from sleep


Thread will wake up automatically to execute the next instruction after sleep() after the thread has slept for the requested amount of time. Nothing needs to be done for waking up the thread unless it should be awaken before the requested amount of time.  

Termination of the Thread by itself


Thread will terminate it’s execution by itself in two ways apart from the advanced techniques like signaling etc. One is normal termination where the thread will complete the execution of the method provided for it at the creation. Other way is the thread calling pthread_exit() function by itself so that it gets killed before completion of its run.  pthread_exit() is normally used when the thread may decide to kill itself in response to some condition satisfied at the runtime. Here is the code snippet for the thread termination using pthread_exit() function.
                        ………………………………
                        // function that will be executed by the thread after  it is created
                        void *printNameOnThread(void *name){
            int i;
            char* threadName = (char*)name;
            for(i=0; i<50; ++i) {
                        printf("\nPrinting my name : %s for %d time", threadName, i);
                        /* pthread_exit() stops the execution of the  thread suddenly when the i takes a value of 25.
                            if the pthread_exit() function is not used in the following block this for loop will execute 50 times                                                      and thread will get terminated after that normally.
                        */
                        if(i==25) {
                        printf("\n* Requesting thread to terminate ", threadName);
                                    pthread_exit(NULL);
                        /* this statement will never be executed because thread dies after executing pthread_exit() statement */
                        printf("\n*Requested thread to terminate ", threadName);
                        }
                                    
            }
            /*  this statement will never be executed because thread dies after executing pthread_exit() statement */
           printf("\n* Completed Execution On Thread : %s ", threadName);
}
……………………………

                    result = pthread_create (pThreadID, NULL, printNameOnThread, (void*)threadName);
                    ……………………………    

Terminate of the Threads from other Thread


Threads can be killed from some other threads in different ways. Important ways are canceling and killing the threads. In this section only cancellation is explained. In the coming parts of the tutorial  killing the threads with signals will be explained. Threads when canceled, depending on their cancellation status they may or may not terminate their execution. pthread_create() should be used to cancel a thread from some other thread.  pthread_t instance of the thread to be terminated will be passed as a parameter to it.  Also a thread can set a cancellation point for itself where the thread will attempt to terminate itself.  This can be done using pthread_testcancel () function.

 Thread's termination will depend on the cancellation state. It can be set using pthread_setcancelstate() function. The parameters to it are new state of the thread and a pointer to integer to which the old state will be set after changing the cancellation state of the thread. The possible values for cancellation state are the following

Cancellation type of the threads determine how and when the threads will be terminated. It can be set using pthread_setcanceltype() function. The parameters to it are new type of the thread and a pointer to integer to which the old type will be set after the cancellation type is changed. The possible values of the cancellation type are the following

Here are the code snippets for illustrating the usage.
                        ………………………………
                        // function that will be executed by the thread after  it is created
                        void *printNameOnThread(void *name){
int i, oldState, oldType ;
……………………………………
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldState) != 0) {……………….}
………………………………….
if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState) != 0) {……………….}
………………………………….
if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,&oldType) != 0) {……………….}
………………………………….
if(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldType) != 0) {……………….}
………………………………….
pthread_testcancel();
……………………………………………
                        }
                        ……………………………………..  
                        int main(){
            int i,j;
            pthread_t threadID1, threadID2, threadID3, threadID4, threadID5;

            /* create and start 5 threads whose cancellation policy is set later in the method these threads execute */
            runThread("T#1", &threadID1);
            runThread("T#2", &threadID2);
            runThread("T#3", &threadID3);
            runThread("T#4", &threadID4);
            runThread("T#5", &threadID5);
            
            /* let those newly created threads run for a while */
            sleep(5);
            
            /* cancel 4 of the threads from the main/current/default thread */
            cancelThread(threadID1);
            cancelThread(threadID2);
            cancelThread(threadID3);
            cancelThread(threadID4);

            /* let this thread wait till the last thread dies when it's counter reaches 40 and when the cancepllation will be done by itself */
            joinThread(threadID5);
}

SourceCode Description

Create.c

Create.c demonstrates the creation of threads and their termination due to death of process. printNameOnThread() function  is the one executed by the threads after they are created. runThread() creates the new thread and in turn associates the thread with the thread’s function with a pointer to a function as a  parameter. main() function creates the threads and enters an empty for loop so that the newly created threads execute for some time and when the for loop execution is complete, program terminates along with the newly created  threads.

Join.c

Join.c demonstrate the creation of new threads and making the main thread to wait till the newly created threads complete their execution. printNameOnThread() function  is the one executed by the threads after they are created. runThread() creates the new thread and in turn associates the thread with the thread’s function with a pointer to a function as a  parameter. waitForThreadToFinish() function makes the thread invoking the function to wait for the thread represented by threadID parameter to complete it’s execution. main() function creates two threads and makes the main thread to wait for completion of the new threads.

Once.c

Once.c demonstrates the single time initialization for threads. initializeForThreading() function will be invoked for doing the initialization required for threads. But here it simply prints a message to the console to indicate that this function is invoked and executed. main() method invokes the initialization function twice and the function will be executed only once.

SelfEqual.c

SelfEqual.c demonstrates getting the identity of a thread and comparing the threads for equality. main() method acquires the identity of a thread twice and compares them. Since the information is corresponding to a single thread they will be equal.

Exit.c

Exit.c demonstrates the termination of the thread by itself based on some runtime condition. printNameOnThread() function  is the one executed by the threads after they are created. runThread() creates the new thread and in turn associates the thread with the thread’s function with a pointer to a function as a  parameter. waitForThreadToFinish() function makes the thread invoking the function to wait for the thread represented by threadID parameter to complete it’s execution. main() function creates the  thread and makes the main thread to wait for completion of the new threads. But in printNameOnThread() function, when the value of  the variable i reaches 25, then the thread will make a call to pthread_exit() function that terminates the thread.

Cancel.c

Cancel.c demonstrates the termination of the thread by other threads using cancellation and also the termination of thread by itself using cancellation points. printNameOnThread() function  is the one executed by the threads after they are created. This method according to the thread name sets different cancellation policies for each thread and for the fifth thread it will set a cancellation point to terminate itself. runThread() creates the new thread and in turn associates the thread with the thread’s function with a pointer to a function as a  parameter. waitForThreadToFinish() function makes the thread invoking it to wait for the thread represented by threadID parameter to complete it’s execution. main() function creates 5 threads and sleeps for some time for allowing the newly created threads to run for some time. Then it cancels first 4  threads. After that it makes the main thread to wait for completion of the new threads. But since the fifth thread has set a cancellation point for itself it will terminate in the middle of it's execution.