Home »
C programming language
Multithreading in C/C++ with Examples
C/C++ | Multithreading: In this tutorial, we will learn about the multithreading, what is multithreading, and how to implement that in C/C++ programming?
By Radib Kar Last updated : April 20, 2023
In this article, we are going to see what is multithreading and why do we need this and how we can implement multithreading in C?
What is Multithreading in C/C++?
Concurrent programming & parallelism is one of the most common features that has been used in the industry level very robustly. Since the CPUs has been advanced based or their performances, the number of cores, developers are also supposed to take advantage of those in software level too. To understand multithreading, we need to understand concurrency. For example, we all use a browser, as I use Firefox. While you open Firefox application, you can use multiple tabs simultaneously. Maybe in one tab, you stream music, in another tab, you play video and in some other tab, you browse your information. Though we are running multiple tabs simultaneously, we are running under single application only. So the application is the main process while the tabs can be thought of as threads running independently with some common shared resources. This is what, known as concurrency.
Now, let's look from the coding point of view. What can be multithreading within coding? Suppose, you are reading a huge file line by line. Say, you are currently reading this creating a single process only(without multithreading). In this case, you are reading lien by line and it will take n*x amount of time given is the number of lines and x is the amount of time needed to read a single line. Now, say you opted for multithreading. You have a good number of CPU cores and you created a thread pool with a fixed number of threads say y which is a good match with the number of CPU cores you have. In this case, you coded in such a way that the first thread will read 1st line, the second thread will read the second line, the yth thread will read the yth line. Now, since all threads running concurrently, you can read y lines in x seconds. The first thread will again read (y+1)th line and so on. So here the total time taken will be much less and roughly it will take time around (n*x)/y.
This is the power of multithreading. Not only on independent cases, say there is a case where you want to create two threads and you need to finish one thread before the other one so that the data integrity maintains.
How to Implement Multithreading?
Multithreading is C is maintained by OS. C doesn't have any additional support for multithreading. Rather it supports POSIX thread APIs which are available on OS like GNU/LINUX, Solaris, macOS X.
The threading APIs are supported by header <pthread.h>
1. Creating a thread in C
Each thread is a pthread_t object that has a unique pthread_t id. Two different threads can't have same pthread_t id. The API that's used to create a thread object is pthread_create()
The syntax of the API is like below:
pthread_create(
pthread_t* id,
pthread_attr_t* attribute,
void* function, void* arg
);
Where,
- pthread_t* id = pointer to the thread id of this thread
- pthread_attr_t* attribute = Sets attributes of a thread, mostly we pass NULL to this
- void* function = name of the worker function that you want to run on the created thread
- void* arg = arguments of the worked function
First two arguments are more on the thread side and programmer is not bothered about that as most of the cases we pass the reference to the id & NULL respectively.
Now if the worker function is void* then, it is fine, otherwise, you have to typecast it. For example, say the signature of the worker function is
Int myworker(void*)
Then we need to typecast myworker as (void* (*)(void*))&myworker
Now if the worker function has more than one arguments, then we need to create a struct and need to typecast that to void*.
For example, worker function has one int and one char as arguments.
Then create a struct,
struct myarg{
Int a;
Char b;
};
typedef struct myarg myarg;
Now, typecast it to (void* )(&myarg)
This is how you tackle different scenarios while creating the thread.
2. Waiting for the child thread to finish
This is a very important step for threading. Say, you have created a child thread from your main thread. Both are working on some common resources. You need your child thread to finish at some point from where the parent thread can further take on. See the below scenario.
Here, at some point in the main thread, you create a child thread. So now both the main thread and the child thread are executing parallel, but at some further point in the main thread you have a scenario where you have to ensure that the child thread has finished, otherwise, there might be a problem with data integrity or something else. Here there can be two cases, one is the child thread finishes its execution before the main thread reaches that point. This is the case which is not our concern. But there can be the case where the child thread is in still execution but the main thread has reached that point. In such cases, we need to halt the main thread forcibly for the child thread to finish. This is known as busy waiting. The API we use to implement this is pthread_join()
The syntax of the API is like below:
pthread_join(p_thread* id, void** return_value);
Where,
- p_thread* id = pointer to the thread id of the thread that has to be finished (child thread)
- void** return_value = reference to the return value from the child thread(worker function )
3. Exiting a thread
To exit a thread pthread_exit() is used. If any value has to be returned from the thread, its reference is passed as an argument for this API. All local variables are destroyed and only global or dynamic variables can be returned.
C/C++ Implementation of Multithreading
Below is a sample program where multithreading has been used.
Code
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
static int i;
void* myworker(void* arg)
{
//delay loop to strenghthen the fact that main thread
//is waiting for the child thread to finish
for (int p = 0; p < 10000000; p++)
;
i = 5;
return NULL;
}
int main()
{
pthread_t id;
i = 3;
printf("In the main thread, i= %d \n", i);
printf("Creating a new thread where we will change the value of i and we will print the changed value here\n");
int failed = pthread_create(&id, NULL, myworker, NULL);
if (failed) {
printf("can't create a child thread, process killed\n");
return 0;
}
else {
printf("Successfully created a child thread\n");
}
//wait for the child thread to finish
pthread_join(id, NULL);
printf("Child thread has finished changing the value of i\n");
printf("i is now %d \n", i);
return 0;
}
Output
In the main thread, i= 3
Creating a new thread where we will change the value of i and we will print the changed value here
Successfully created a child thread
Child thread has finished changing the value of i
i is now 5
How to run multithreading program?
If you have tried to run in some online complier and you have failed and started blaming me, then just hold a minute. As I have already told you that, there are POSIX APIs supported by OS like Linux, Solaris etc. So, first of all, don't try on any online compiler. Try only in some dedicated Linux machine.
Still, you are having some compiler error? Saying that can't resolve reference to pthread related stuff?
That's because you haven't passed the "-lpthread" option which tells compiler pthread related stuff will be linked later. So to run it correctly following are the steps
- Open a Linux terminal.
- Enter the directory where your code is. Say the code name is "code.c"
- To compile: gcc code.c -lpthread or g++ code.c -lpthread
- To run: ./a.out
With GCC compiler
With G++ compiler
If you are still facing problem to run this, please do comment.