Thread Libraries has a collection of functions that useful in creating and controlling threads. Programmers can access these thread libraries using an application programming interface (API). Thread libraries can be the user level library or kernel level library.
If the thread library is implemented at the userspace then code and data of the thread library would reside in user space. In this case, invoking any function from thread library would be a simple function call and it won’t be a system call.
If the thread library is implemented at the kernel space then code and data of the library would reside in the kernel space and would be supported by the operating system. In this case, invoking a function from thread library would be a system call to the kernel. In the section further, we would be discussing three kinds of thread libraries.
Thread Libraries in Operating System
Pthread Library
Pthreads are also termed as POSIX thread library. This can be implemented either at the userspace or at the kernel space. Pthreads library is often implemented at LINUX, UNIX, Solaris, Mac OSX. The Pthread program must always have a pthread.h header file.
To get the basic understanding of how the Pthread is invoked, how the control of the program passes to thread and how the thread get destroyed after completing the operation we will overview a multithreaded program that calculates the summation of nonnegative integers.
#include <pthread.h> #include <stdio.h> int sum; /* this data is shared by the thread(s) */ void *runner(void *param); /* the thread */ int main(int argc, char *argv[]) { pthread_t tid; /* the thread identifier */ pthread_attr_t attr; /* set of thread attributes */ if (argc != 2) { } fprintf(stderr,"usage: a.out <integer value>\n"); return -1; } if (atoi(argv[1]) < 0) { fprintf(stderr,"%d must be>= 0\n",atoi(argv[1])); return -1; } pthread_attr_init(&attr); /* get the default attributes */ pthread_create(&tid,&attr,runner,argv[1]); /* create the thread */ pthread_join(tid,NULL); /* wait for the thread to exit */ printf("sum = %d\n",sum); } void *runner(void *param) /* The thread will begin control in this function */ { inti, upper= atoi(param); sum = 0; for (i = 1; i <= upper; i++) sum += i; pthread_exi t ( 0) ; }
Work Flow of Pthread Program
The variable sum is the global data that would be shared by all the threads in the program.
- The program starts with the main() where it accepts two arguments, first is the argument count and second the argument vector i.e. the string of characters.
- Then it executes the pthread_t tid, this command would generate the thread id you would be creating.
- Then the next statement that would be executed is pthread_attr_t attr which makes the declaration of thread attributes.
- Now this statement if (argc != 2) verifies that argument count is not equal to 2.
- The statement if (atoi(argv[1]) < 0) first converts the value of argv[1] to integer and verifies that it is greater than 0. The command ‘atoi’ is for converting the array to an integer.
- The statement pthread_attr_init(&attr) initiates the default thread attributes.
- The command pthread_create(&tid,&attr,runner,argv[1]) would create a thread. The created thread accepts four arguments first is thread_id this means the created thread is associated to the thread id declared in step 2, with the second argument it accepts the default thread arguments, with the third argument we pass the name of the function where the thread has to begin the execution from here the function is a runner and at last we pass the integer argument that we provided to the program at the command line.
- Now we have two threads the initial thread of main() and the next thread executing runner(). For now, the execution of main() thread is put on hold as it calls the function pthread_join(tid,NULL) this function transfers the control to the thread with thread id ‘tid’ i.e. the thread created to execute runner() function.
- The runner() function will complete the summation operation and would get terminated by calling the function pthread_exi t ( 0) which would again transfer the control to main() and print the summation value.
So the functions we used above i.e. pthread_attr_init(&attr), pthread_create(&tid,&attr,runner,argv[1]), pthread_join(tid,NULL), pthread_exi t ( 0) are the functions in Pthread library we used to create and manage threads.
Win32 Library
Creation of thread in Win2 library is similar to pthread library. To create a thread using the Win32 library always include windows.h header file in the program. The Win32 thread library is a kernel-level library which means invoking the Win32 library function results in a system call.
Now we will see how we can create and manage threads using the functions in Win32 thread library.
#include <Windows.h> #include <stdio.h> DWORD Sum; /* data is shared by the thread(s) */ DWORD WINAPI Sumrnation(LPVOID Param) /* the thread runs in this separate function */ { DWORD Upper = *(DWORD*)Param; for (DWORD i = 0; i <= Upper; i++) Sum += i; return 0; } int main(int argc, char *argv[]) { DWORD Threadid; HANDLE ThreadHandle; int Param; /* perform some basic error checking */ if (argc != 2) { fprintf(stderr,"An integer parameter is required\n"); return -1; } Param = atoi(argv[1]); if (Param < 0) { fprintf(stderr,"An integer>= 0 is required\n"); return -1; } /* create the thread*/ ThreadHandle = CreateThread( NULL, /*default security attributes*/ 0, /*default stack size*/ Summation, /* thread function*/ &Param, /*parameter to the thread function*/ 0, /*default creation flags*/ &Threadid); /* returns the thread identifier*/ if (ThreadHandle != NULL) { /* now wait for the thread to finish*/ WaitForSingleObject(ThreadHandle,INFINITE); /* close the thread handle*/ CloseHandle(ThreadHandle); printf("surn = %d\n" ,Sum); } }
Workflow in Win32 Program
In the program below the variable sum has the global data shared by all the threads in the program.
- The execution of the program starts with the main() function which accepts two arguments first is the argument count and second is the argument vector i.e. the string of characters.
- The next statement DWORD Threadid declares the thread id which would be created further in this program.
- The statement HANDLE ThreadHandle creates a pointer ‘ThreadHandle’ that will be used to access the Win32 library functions.
- The next two if statements perform some basic error checking.
- The statement ThreadHandle = CreateThread(NULL, 0, Summation, &Param, 0, &Threadid) creates a thread and gives its reference to ThreadHandle.
The CreateThread() function accept six arguments where Null is for default security attributes, 0 is the default stack size, Summation is the separate thread function, &Param is the parameters to thread function, 0 is default flag creation and ThreadID is the id of the thread that is to be associated to the Summation thread function. - The next if function waits for the Summation thread to get complete with the function WaitForSingleObject(ThreadHandle, INFINITE) and once it gets complete the thread is terminated with CloseHandle(ThreadHandle) function. Finally, the sum is displayed.
So here, the functions CreateThread(), WaitForSingleObject(), CloseHandle() are the function in Win32 thread library which are used to create and manage threads.
Java Thread Library
You must have seen that mostly the java virtual machine JVM runs on the top of the host operating system. That’s why java threads are created and controlled by using the available library at the host operating system.
Therefore, in the Windows operating system, the java threads are implemented using Win32 API and in operating systems such as Linux and UNIX, the java thread is implemented using Pthread library. In a Java program, there is at least one thread of control. Well, there are two methods to creating a thread in Java program first you can derive a new class from a Thread class and override it’s run() method. The second method is to define a class and implement a Runnable interface to it, the second method is the most common method to be used.
class Sum { private int sum; public int getSum() { return sum; } public void setSum(int sum) { this.sum sum; } } class Summation implements Runnable { private int upper; private Sum sumValue; public Summation(int upper, Sum sumValue) { this.upper = upper; this.sumValue = sumValue; } public void run() { int sum = 0; for (int i = 0; i <= upper; i++) sum += i; sumValue.setSum(sum); } } public class Driver { public static void main(String[] args) { if (args.length > 0) { if (Integer.parseint(args[O]) < 0) System.err.println(args[O] + "must be>= 0."); else { II create the object to be shared Sum sumObject = new Sum(); int upper= Integer.parseint(args[O]); Thread thrd =new Thread(new Summation(upper, sumObject)); thrd.start(); try { thrd. join () ; System.out.println ("The sum of "+upper+" is "+sumObject.getSum()); } catch (InterruptedException ie) { } } } else System.err.println("Usage: Summation <integer value>"); } }
Workflow of the Java Program
The Java program above has three classes Sum, Summation and the Driver class. The Sum class has two methods, the getSum() method returns the sum value and the setSum() method assigns a value to sum variable. The Summation class has the logic that has to be run by the thread. The Driver class is the main class of execution.
Now let us understand the creation and execution of the thread in the Java program above.
- From the command line, you have entered the argument value let us suppose 5 which is passed to the main() method. The main method accepts the argument into the string vector.
- The first if statement checks the user passed argument length and we know it greater than 0.
- It further checks that if the args[0] (which is 5 in our case) is less than 0 by converting that string to integer (as the main has accepted the argument into string vector). If the args[0] is less than 0 then an error is displayed.
But as in our case, the args[0] (i.e. 5) is not less than 0 the else statement is executed - The else statement creates an object for Sum class i.e. sumObject.
- Now in a local integer variable ‘upper’ the value of args[0] is assigned by using parseInt() method which converts the string to an integer.
- Next, a thread object thrd is created next we have to pass Summation runnable instance to it. As the Summation instance, it created its constructor would be executed, to its constructor, we have passed two arguments variable upper i.e. 5 and an object of Sum class i.e. sumObject. The constructor Summation would assign the values accepted in its argument to its instance variable. Now invoking thrd.start() creates a new thread which executes run() of Summation class as it is implemented using Runnable interface.
- The run() method calculates the sum of the first 5 natural numbers and sets the sum value to an instance variable sum of Sum class and control return back to main() again.
- The thrd.join() method has blocked the execution of rest of the main() until the threads have completed its execution. Next, the value of sum is printed.
In the Java program above there were two threads one executes the main() and other executes the run().
So these are the three thread libraries that can be used to create and manage threads. In Win32 and Pthread thread libraries, the threads can easily share the data as the data can be declared globally. But this is not the case with java program. As Java is an object-oriented language there is no concept of the global variable instead the reference of a variable to be shared is passed to the required thread.
Leave a Reply