Open In App

Multithreading in C++

Last Updated : 16 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Multithreading is a technique where a program is divided into smaller units of execution called threads. Each thread runs independently but shares resources like memory, allowing tasks to be performed simultaneously. This helps improve performance by utilizing multiple CPU cores efficiently. Multithreading support was introduced in C++11 with the introduction of <thread> header file.

Create a Thread

The std::thread class represent the thread. Threading an instance of this class will create a thread with the given callable as its task.

C++
thread thread_name(callable);

where,

  • thread_name: It is object of thread class.
  • callable: It is a callable object like function pointer, function object.

Example:

C++
//Driver Code Starts{
#include <bits/stdc++.h>
using namespace std;

//Driver Code Ends }

// Function to be run by the thread
void func() {
    cout << "Hello from the thread!" << endl;
}

int main() {
    
    // Create a thread that runs 
    // the function func
    thread t(func);
    
    // Main thread waits for 't' to finish
    t.join();  
    cout << "Main thread finished.";

//Driver Code Starts{
    return 0;
}

//Driver Code Ends }


Output

Hello from the thread!
Main thread finished.

A callable (such as a function, lambda, or function object) is passed to a thread. The callable is executed in parallel by the thread when it starts. like, thread t(func); creates a thread that runs the func function. We can also pass parameters along with callable, like this thread t(func, param1, param2);

In C++, callable can be divided into 4 categories:

  • Function
  • Lambda Expression
  • Function Object
  • Non-Static or static Member Function

Function Pointer

A function can be a callable object to pass to the thread constructor for initializing a thread.

C++
//Driver Code Starts{
#include <bits/stdc++.h>
using namespace std;

//Driver Code Ends }

// Function to be run 
// by the thread
void func(int n) {
    cout << n;
}

int main() {
    
    // Create a thread that runs 
    // the function func
    thread t(func, 4);

//Driver Code Starts{
    
    // Wait for thread to finish
    t.join();
    return 0;
}

//Driver Code Ends }


Output

4

Lambda Expression

Thread object can also be using a lambda expression as a callable. We can pass directly inside the thread object.

C++
//Driver Code Starts{
#include <iostream>
#include <thread>

using namespace std;

int main() {
    int n = 3;
    
//Driver Code Ends }

    // Create a thread that runs 
    // a lambda expression
    thread t([](int n){
        cout << n;
    }, n);

//Driver Code Starts{

    // Wait for the thread to complete
    t.join();
    return 0;
}

//Driver Code Ends }


Output

3

Function Objects

Function Objects or Functors can also be used for a thread as callable. To make functors callable, we need to overload the operator parentheses operator ().

C++
//Driver Code Starts{
#include <iostream>
#include <thread>
using namespace std;

//Driver Code Ends }

// Define a function object (functor)
class SumFunctor {
public:
    int n;
    SumFunctor(int a) : n(a) {}

    // Overload the operator() to 
    // make it callable
    void operator()() const {
        cout << n;
    }
};

int main() {

    // Create a thread using 
    // the functor object
    thread t(SumFunctor(3));

//Driver Code Starts{

    // Wait for the thread to 
    // complete
    t.join();
    return 0;
}

//Driver Code Ends }


Output

3

Non-Static and Static Member Function

We can also use thread using the non-static or static member functions of a class. For non-static member function, we need to create an object of a class but it’s not necessary with static member functions.

C++
//Driver Code Starts{
#include <iostream>
#include <thread>

using namespace std;

//Driver Code Ends }

class MyClass {
public:
    // Non-static member function
    void f1(int num) {
        cout << num << endl;
    }

    // Static member function that takes one parameter
    static void f2(int num) {
        cout << num;
    }
};

int main() {
    
    // Member functions 
    // requires an object
    MyClass obj;
    
    // Passing object and parameter
    thread t1(&MyClass::f1, &obj, 3);
    
    t1.join(); 
    
    // Static member function can 
    // be called without an object
    thread t2(&MyClass::f2, 7);

//Driver Code Starts{
    
    // Wait for the thread to finish
    t2.join();  

    return 0;
}

//Driver Code Ends }


Output

3
7

Thread Management

In C++ thread library, various functions are defined to manage threads that can be reused to perform multiple tasks. Some of the are listed below:

Classes/MethodsDescription
join()It ensures that the calling thread waits for the specified thread to complete its execution.
detach()Allows the thread to run independently of the main thread, meaning the main thread does not need to wait.
mutexA mutex is used to protect shared data between threads to prevent data races and ensure synchronization.
lock_guardA wrapper for mutexes that automatically locks and unlocks the mutex in a scoped block.
condition_variableUsed to synchronize threads, allowing one thread to wait for a condition before proceeding.
atomicManages shared variables between threads in a thread-safe manner without using locks.
sleep_for()Pauses the execution of the current thread for a specified duration.
sleep_until()Pauses the execution of the current thread until a specified time point is reached.
hardware_concurrency()Returns the number of hardware threads available for use, allowing you to optimize the use of system resources.
get_idRetrieves the unique ID of the current thread, useful for logging or debugging purposes.

Problems with Multithreading

Multithreading improves the performance and utilization of CPU, but it also introduces various problems:

  • Deadlock
  • Race Condition
  • Starvation

Deadlock

A deadlock occurs when two or more threads are blocked forever because they are each waiting for shared resources that the other threads hold. This creates a cycle of waiting, and none of the threads can proceed.

Race Condition

A race condition occurs when two or more threads access shared resources at the same time, and at least one of them modifies the resource. Since the threads are competing to read and write the data, the final result depends on the order in which the threads execute, leading to unpredictable or incorrect results.

Starvation

Starvation occurs when a thread is continuously unable to access shared resources because other threads keep getting priority, preventing it from executing and making progress.

Thread Synchronization

In multithreading, synchronization is the way to control the access of multiple threads to shared resources, ensuring that only one thread can access a resource at a time to prevent data corruption or inconsistency. This is typically done using tools like mutexes, locks, and condition variables.

What is a context switch in multithreading?

Context switch is a process in multithreading which stores the state of the running thread so that it can be restored later, while the CPU switches to another thread for execution.



Next Article
Article Tags :
Practice Tags :

Similar Reads