Multithreading in C++ provides many benefits to users, including useful and efficient features and functionalities.
One of the most important and useful features is multithreading.
Even today, multithreading is one of the most used features.
What is Multithreading in C++?
Multithreading is a type of multitasking that allows you to run multiple programs concurrently.
There are two types of multitasking: process-based and thread-based.
Process-based multitasking aids in running multiple programs simultaneously.
Thread-based multitasking helps with running multiple parts of the same program at the same time.
Multithreading means running multiple threads at the same time.
Each thread is responsible for a different task, which allows for many activities to be performed simultaneously.
C++ does not have any built-in support for multithreaded applications; it relies entirely on the operating system.
An example would be if you were to login into Facebook and see a live video on your newsfeed.
You would be able to comment or like the video simultaneously.
How to do Multithreading in C++?
To start a thread, we create a new thread object and pass the code to be executed (i.e. a callable object) into the constructor.
This will launch a new thread that will execute the code specified in the callable.
What is a Thread?
A multithreaded program consists of at least two parts that can run simultaneously.
Each component of such a program is referred to as a thread, and each thread defines a distinct execution path.
Threads are lightweight processes that can execute different parts of a program concurrently.
Threads share memory and other system resources.
Threads are not executed simultaneously, but rather the operating system simulates their execution.
This is called multithreading and is used when parallel execution of tasks leads to more efficient use of system resources.
This tutorial will teach you how to write multithreaded C++ programs using POSIX. POSIX is a set of standards that define how programs should work on UNIX-like operating systems.
Many popular operating systems, such as Linux, FreeBSD, and Mac OS X, follow these standards.
In C++, std::thread is the class that represents a single thread.
To initiate a thread, it is sufficient to create a new thread object and send the code to be executed (i.e., a callable object) into the object’s constructor.
Once the object has been constructed, a new thread is initiated, and the code given in callable is executed.
A callable can be one of the three following: function pointer, function objects, or lambda expression.
Creating Threads in C++
You can initiate the creation of a thread by calling the pthread_create()
function.
Syntax:
pthread_create(Idthread, attr, start_routine, arg)
Parameters:
Idthread
– It is a unique identifier for each thread.
attr
– It is an attribute object that may be used to set multiple thread attributes. You can also provide thread attribute objects or you can setNULL
for default values.
start_routine
– Once the thread has been created, it will immediately begin executing.
arg
– The argument tostart_routine
must be a pointer to void, and it will be passed by reference. If no argument is provided,NULL
will be used.
Example:
#include <iostream>
#include <pthread.h>
using namespace std;
void *child_thread(void *arg)
{
cout << "This is child_thread()" << endl;
pthread_exit(NULL);
}
int main()
{
pthread_t my_thread;
int x;
cout << "Main Function: Creating Thread" << endl;
x = pthread_create(&my_thread, NULL, &child_thread, NULL);
if(x != 0) {
cout << "Error: pthread_create() failed" << endl;
exit(EXIT_FAILURE);
}
pthread_exit(NULL);
}
Output:
Main Function: Creating Thread
This is child_thread()
The code creates a second thread, child_thread()
which prints its message, while the main thread prints another.
NULL attributes in the thread creation method provide its default properties.
The call also passes my_thread
to child_thread
to store a thread handle. If successful, pthread_create()
returns zero; otherwise, it returns an error.
Terminating Threads in C++
By calling the pthread_exit()
method, you can bring any thread to a close.
This function is normally called after a thread has finished its work, and it is not necessary for it to still exist.
Example: Creating threads in C++
#include <iostream>
#include <pthread.h>
using namespace std;
char* ct = "This is the Child Thread";
void* fun(void *ct){
cout << "Created child thread: " << (char*)ct;
}
int main()
{
pthread_t mt;
pthread_create(&mt, NULL, &fun, (void*)ct);
cout << "Created Main thread! \n";
pthread_join(mt, NULL);
exit(EXIT_SUCCESS);
return 0;
}
Output:
Created Main thread!
Created child thread: This is the Child Thread
Passing Arguments to Threads in C++
Using a structure, you can pass many parameters to threads. Any data type can be passed to a thread callback.
Example:
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define x 3
struct data{
int thread_id;
char *msg_text;
};
void *greeting(void *thread_arg) {
struct data *val;
val = (struct data *) thread_arg;
cout << "Thread ID : " << val->thread_id ;
cout << "\nMessage : " << val->msg_text << endl;
pthread_exit(NULL);
}
int main () {
pthread_t threads[x];
struct data td[x];
int rc;
int i;
for( i = 0; i < x; i++ ) {
cout <<"Creating Thread: " << i << endl;
td[i].thread_id = i;
td[i].msg_text = "Sample Message Text!";
rc = pthread_create(&threads[i], NULL, greeting, (void *)&td[i]);
if (rc) {
cout << "Error: Unable to create thread, " << rc << endl;
exit(0);
}
}
pthread_exit(NULL);
}
Output:
Creating Thread: 0 Creating Thread: 1 Thread ID : 0 Message : Sample Message Text! Creating Thread: 2 Thread ID : 2 Message : Sample Message Text! Thread ID : 1 Message : Sample Message Text!
Joining and Detaching Threads in C++
In C++, you also have the ability to join or detach threads.
join() function in C++
The join()
function must be used to join a thread.
The main thread will only terminate after the child thread has finished.
The main thread will wait for the child thread to complete execution.
Syntax:
thread_name.join();
The joinable()
function returns a bool value that indicates whether or not a thread can be joined.
Syntax:
thread_name.joinable();
detach() function in C++
The detach() function allows you to detach a thread from the parent thread so that the main and child threads
can execute independently.
Example:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
string str;
void* fun(void*)
{
sleep(1);
cout << "Created Child thread!" << str << endl;
}
int main()
{
pthread_t threadname[5];
for(int i=0; i<5; i++)
{
cout << "Created > threadname[" << i << "]" << str << endl;
pthread_create(&threadname[i], NULL, &fun, NULL);
pthread_detach(threadname[i]);
}
exit(EXIT_SUCCESS);
return 0;
}
Output:
Created > threadname[0] Created > threadname[1] Created > threadname[2] Created > threadname[3] Created > threadname[4]
Advantages of Multithreading in C++
- Multithreading performs quicker on a system with several CPUs.
- This allows you to decrease performance and concurrency.
- It allows you to access multiple programs simultaneously.
- It also allows an application to make optimal use of available CPU.
Summary
This tutorial covered the definitions of thread and multithreading in C++.
Additionally, we discussed how to create and terminate a thread.
Then, we discussed the C++ procedure for joining and detaching threads. We discussed how arguments could be passed to threads.