In the part-II (Thread creation and Identification) of the Linux Thread series, we discussed about thread IDs, how to compare two thread IDs and how to create a thread.
In this article we will mainly focus on how a thread is terminated.
Linux Threads Series: part 1, part 2, part 3 (this article).
C Thread Example Program
If we take the same example as discussed in part-II of this series :
#include<stdio.h> #include<string.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h> pthread_t tid[2]; void* doSomeThing(void *arg) { unsigned long i = 0; pthread_t id = pthread_self(); if(pthread_equal(id,tid[0])) { printf("\n First thread processing\n"); } else { printf("\n Second thread processing\n"); } for(i=0; i<(0xFFFFFFFF);i++); return NULL; } int main(void) { int i = 0; int err; while(i < 2) { err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL); if (err != 0) printf("\ncan't create thread :[%s]", strerror(err)); else printf("\n Thread created successfully\n"); i++; } sleep(5); return 0; }
Did you observe the ‘sleep()’ function being used? Did you get a question about why sleep() is being used? Well if you did then you are at the correct place to get the answer and if you did not then also its going to be a good read ahead.
If I remove the sleep() function from the code above and then try to compile and run it, I see the following output :
$ ./threads Thread created successfully First thread processing Thread created successfully
But if I run it with sleep() enabled then I see the output as :
$ ./threads Thread created successfully First thread processing Thread created successfully Second thread processing
So we see that the log ‘Second thread processing’ is missing in case we remove the sleep() function.
So, why does this happen? Well, this happened because just before the second thread is about to be scheduled, the parent thread (from which the two threads were created) completed its execution. This means that the default thread in which the main() function was running got completed and hence the process terminated as main() returned.
Thread Termination
As already discussed above that each program starts with at least one thread which is the thread in which main() function is executed. So maximum lifetime of every thread executing in the program is that of the main thread. So, if we want that the main thread should wait until all the other threads are finished then there is a function pthread_join().
#include <pthread.h> int pthread_join(pthread_t thread, void **rval_ptr);
The function above makes sure that its parent thread does not terminate until it is done. This function is called from within the parent thread and the first argument is the thread ID of the thread to wait on and the second argument is the return value of the thread on which we want to the parent thread to wait. If we are not interested in the return value then we can set this pointer to be NULL.
If we classify on a broader level, then we see that a thread can terminate in three ways :
- If the thread returns from its start routine.
- If it is canceled by some other thread. The function used here is pthread_cancel().
- If its calls pthread_exit() function from within itself.
The focus here would be on pthread_exit(). Its prototype is as follows :
#include <pthread.h> void pthread_exit(void *rval_ptr);
So we see that this function accepts only one argument, which is the return from the thread that calls this function. This return value is accessed by the parent thread which is waiting for this thread to terminate. The return value of the thread terminated by pthread_exit() function is accessible in the second argument of the pthread_join which just explained above.
C Thread Termination Example
Lets take an example where we use the above discussed functions :
#include<stdio.h> #include<string.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h> pthread_t tid[2]; int ret1,ret2; void* doSomeThing(void *arg) { unsigned long i = 0; pthread_t id = pthread_self(); for(i=0; i<(0xFFFFFFFF);i++); if(pthread_equal(id,tid[0])) { printf("\n First thread processing done\n"); ret1 = 100; pthread_exit(&ret1); } else { printf("\n Second thread processing done\n"); ret2 = 200; pthread_exit(&ret2); } return NULL; } int main(void) { int i = 0; int err; int *ptr[2]; while(i < 2) { err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL); if (err != 0) printf("\ncan't create thread :[%s]", strerror(err)); else printf("\n Thread created successfully\n"); i++; } pthread_join(tid[0], (void**)&(ptr[0])); pthread_join(tid[1], (void**)&(ptr[1])); printf("\n return value from first thread is [%d]\n", *ptr[0]); printf("\n return value from second thread is [%d]\n", *ptr[1]); return 0; }
In the code above :
- We created two threads using pthread_create()
- The start function for both the threads is same ie doSomeThing()
- The threads exit from the start function using the pthread_exit() function with a return value.
- In the main function after the threads are created, the pthread_join() functions are called to wait for the two threads to complete.
- Once both the threads are complete, their return value is accessed by the second argument in the pthread_join() call.
The output of the above code comes out as :
$ ./threads Thread created successfully Thread created successfully First thread processing done Second thread processing done return value from first thread is [100] return value from second thread is [200]
So we see that both the threads execute completely and their return value is accessed in the main function.
Comments on this entry are closed.
great article series, really helped me understand threading in a concise way.
really a good work .It clarified some of my doubts on threads.thanks..
Very good article.
Very nice article for beginners.Thanx.
Nice article . .. Thanx
Useful. thanks a lot!
Good article. Clearly explains concept .thanks
Very good article.Well understanding.
after copying above programme in gcc compiler it shows
undefined reference to ‘pthread_create’
undefined reference to ‘pthread_join’
In your example on Thread Termination, you have the following lines of code in main()
pthread_join(tid[0], (void**)&(ptr[0])); // line 1
pthread_join(tid[1], (void**)&(ptr[1])); // line 2
So does the main thread start waiting as soon as it executes line 1?
If that is the case, what would happen if:
1. Main thread executes line 1 and starts waiting for the first thread to finish.
2. In the meantime, second thread finishes (before the first thread) and returns some value.
3. Main thread has not yet executed line 2 (which means main thread has not received the return value from second thread)
4. First thread finishes and main thread is then able to execute line 2
In that case will we lose (drop) the return value of the 2nd thread which has already exited before main called pthread_join on it?
– vivek
Well written and well explained. (needs some typo correction though)
it has nice examples too
This explanation was something I needed to do my assignment.
I got here and it was the starting point…
Thank you very much.
WE need to create the threads as JOINABLE, for pthread_join to work.
I am not verified. But Good Explanation….Thanks dude..
Beautiful explanation.Thanks a lot.
very nice explanation.
Very great article thank you so much
Very nice articles! Thanks