During my 8th semester at University Of Moratuwa, I have enrolled to this module called Concurrent Module and I thought of sharing the things I learnt.
What is multithreading?
Multithreading is the ability of a program or an operating system process to manage its use by more than one user at a time and to even manage multiple requests by the same user without having to have multiple copies of the programming running in the computer. Each user request for a program or system service (and here a user can also be another program) is kept track of as a thread with a separate identity. As programs work on behalf of the initial request for that thread and are interrupted by other requests, the status of work on behalf of that thread is kept track of until the work is completed.
To understand the basic multithreading concepts, samples programmes have been developed using C. POSIX Threads, usually referred to as Pthreads, is an execution model that exists independently from a language, as well as a parallel execution model. It allows a program to control multiple different flows of work that overlap in time. Each flow of work is referred to as a thread, and creation and control over these flows is achieved by making calls to the POSIX Threads API. Implementations of the API are available on many Unix-like POSIX-conformant operating systems such as FreeBSD, NetBSD, OpenBSD, Linux, Mac OS X and Solaris, typically bundled as a library libpthread. DR-DOS and Microsoft Windows implementations also exist: within the SFU/SUA subsystem which provides a native implementation of a number of POSIX APIs, and also within third-party packages such as pthreads-w32, which implements pthreads on top of existing Windows API.
All C programs using pthreads need to include the pthread.h header file (ie: #include <pthread.h>). There are four steps to creating a basic threaded program:
1: Define thread reference variables
The variable type
pthread_t is a means of referencing threads. There needs to be a
pthread_t variable in existence for every thread being created. Something like
pthread_t thread0; will do the trick.
2: Create an entry point for the thread
When creating a thread using pthreads, you need to point it to a function for it to start execution. The function must return
void * and take a single
void * argument. For example, if you want the function to take an integer argument, you will need to pass the address of the integer and dereference it later. This may sound complicated but, as is shown below, it’s pretty simple. An example function signature would be
void *my_entry_function(void *param);
3: Create the thread
pthread_t variable has been defined and the entry point function created, we can create the thread using
pthread_create. This method takes four arguments: a pointer to the
pthread_t variable, any extra attributes (don’t worry about this for now – just set it to NULL), a pointer to the function to call (ie: the name of the entry point) and the pointer being passed as the argument to the function. Now there’s a lot of pointers in that call, but don’t stress – it’s not as tricky as it sounds. This call will look something like
pthread_create(&thread0, NULL, my_entry_function, ¶meter);
4: Join everything back up
When the newly-created thread has finished doing it’s bits, we need to join everything back up. This is done by the
pthread_join function which takes two parameters: the
pthread_t variable used when
pthread_create was called (not a pointer this time) and a pointer to the return value pointer (don’t worry about this for now – just set it to NULL). This call will look something like
And that’s all there is to it. The function used as the thread entry point can call other functions, create variables or do anything any other function can do. It can also use the variables set by the other thread.
When compiling the program, you will also need to add
-lpthread to the compile command. ie:
gcc program.c -o program -lpthread
Below is a minimum example of a threaded application. It creates two numbers, x and y, and creates a second thread. The first thread increments y until it has the value of 100, while the second thread increments x until it has the value of 100 at the same time. When this is done, it joins the second thread back with the main program and prints the results. Note how, even though x was changed by the second thread, it has been changed for the main program too!
This code will print something like:
x: 0, y:0 y increment finished x increment finished x: 100, y: 100