Skip to content
geeksforgeeks
  • Tutorials
    • Python
    • Java
    • Data Structures & Algorithms
    • ML & Data Science
    • Interview Corner
    • Programming Languages
    • Web Development
    • CS Subjects
    • DevOps And Linux
    • School Learning
    • Practice Coding Problems
  • Courses
    • DSA to Development
    • Get IBM Certification
    • Newly Launched!
      • Master Django Framework
      • Become AWS Certified
    • For Working Professionals
      • Interview 101: DSA & System Design
      • Data Science Training Program
      • JAVA Backend Development (Live)
      • DevOps Engineering (LIVE)
      • Data Structures & Algorithms in Python
    • For Students
      • Placement Preparation Course
      • Data Science (Live)
      • Data Structure & Algorithm-Self Paced (C++/JAVA)
      • Master Competitive Programming (Live)
      • Full Stack Development with React & Node JS (Live)
    • Full Stack Development
    • Data Science Program
    • All Courses
  • C++ Data Types
  • C++ Input/Output
  • C++ Arrays
  • C++ Pointers
  • C++ OOPs
  • C++ STL
  • C++ Interview Questions
  • C++ Programs
  • C++ Cheatsheet
  • C++ MCQ
  • C++ Projects
  • C++ Exception Handling
  • C++ Memory Management
Open In App
Next Article:
Thread Synchronization in C++
Next article icon

Thread Synchronization in C++

Last Updated : 01 Jan, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

In C++ multithreading, synchronization between multiple threads is necessary for the smooth, predictable, and reliable execution of the program. It allows the multiple threads to work together in conjunction by having a proper way of communication between them. If we do not synchronize the threads working on a shared resource properly, it may cause some of the concurrency problems.

Importance of Thread Synchronization

Consider that there is a program that is being used for managing the banking data. Now, assume that two threads are being used for credit and debit in a bank account. Now, assume the following sequence of transactions of a user:

  1. Initial Balance = 300
  2. Credited_process: 400, Current Balance = 700
  3. Debited_process: 500, Current Balance = 200

Now, assume that there is no synchronization between the processes running on the different threads. So, it is possible that the sequence of the operation can be:

  1. Initial Balance: 300
  2. Debited_process: 500, Current Balance = 300
  3. Credit_process: 400, Current Balance = 700

Due to this change in the sequence, the user wont be able to withdraw his/her money from the bank account even though he had credited enough money in the account. Here, both credit_process and debit_process threads can be synchronized so that when there is a simultaneous credit and debit requests, it should first execute the credit request.

There can be many such concurrency issues that arises due to non-synchronized operations. Some of them are:

  1. Race Condition
  2. Deadlocks
  3. Starvation

Thread Synchronization in C++

In C++, thread synchronization is possible using the following methods:

1. Mutex in C++

Mutex is a synchronization primitive that locks the access to the shared resource if some thread is already accessing it.

Example

Let us take an example of a code snippet given below -

C++
// C++ program to illustrate the execution of multithreading // program without any synchronization #include <iostream> #include <thread> using namespace std;  // shared data double val = 0; int cnt = 0;  void add(double num) {     val += num;     cnt++;     cout << "Thread " << cnt << ": " << val << endl; }  // driver code int main() {     thread t1(add, 300);     thread t2(add, 600);     t1.join();     t2.join();     cout << "After addition : " << val << endl;     return 0; } 


Output

Thread Thread 22: : 900900    After addition : 900

In the above code snippet, we created two threads and we have an add function which in turn adds the values. Both the threads, t1 and t2 go to the add function simultaneously. Now, it becomes difficult to decide which thread will execute first and modify the value of num as both of them move to the add function simultaneously. Such a condition is called race condition. Thus, we should apply thread synchronization to avoid this race condition.

Here, we will apply mutex to achieve synchronization.

C++
// C++ program to illustrate the use of mutex locks to // synchronize the threads #include <iostream> #include <mutex> #include <thread> using namespace std;  // shared lock double val = 0;  // mutex lock mutex m;  int cnt = 0;  void add(double num) {     m.lock();     val += num;     cnt++;     cout << "Thread " << cnt << ": " << val << endl;     m.unlock(); }  // driver code int main() {     thread t1(add, 300);     thread t2(add, 600);     t1.join();     t2.join();     cout << "After addition : " << val << endl;     return 0; } 


Output

Thread 1: 300  Thread 2: 900  After addition : 900

or

Thread 1: 600
Thread 2: 900
After addition : 900

Note: In the above code after applying mutex we can get any of the two outputs as shown above. This is because, after applying mutex we have prevented both the threads from entering inside the add() function together, but, either thread t1 or thread t2 enters the add() function first and therefore the output varies with respect to that.

Now, both the threads will not be able to access the critical section at the same time as we have applied lock . Thus, here using mutex we were able to achieve thread synchronization.

2. Condition Variable in C++

The condition variable is another such synchronization primitive but it is mainly used to notify the threads about the state of the shared data. It is used with the mutex locks to create processes that automatically wait and notify the state of the resource to each other.

Example

C++
// C++ program to illustrate the use of condition variable #include <condition_variable> #include <iostream> #include <mutex> #include <thread>  using namespace std;  // condition variable and mutex lock condition_variable cv; mutex m;  // shared resource int val = 0;  void add(int num) {     lock_guard<mutex> lock(m);     val += num;     cout << "After addition: " << val << endl;     cv.notify_one(); }  void sub(int num) {     unique_lock<mutex> ulock(m);     cv.wait(ulock,             [] { return (val != 0) ? true : false; });     if (val >= num) {         val -= num;         cout << "After subtraction: " << val << endl;     }     else {         cout << "Cannot Subtract now!" << endl;     }     cout << "Total number Now: " << val << endl; }  // driver code int main() {     thread t2(sub, 600);     thread t1(add, 900);     t1.join();     t2.join();     return 0; } 


Output

After addition: 900
After subtraction: 300
Total number Now: 300

Explaination

Here, in this program we first create two threads and then we try to perform addition first followed by subtraction. But as we can see in the above program, we passed the thread t2 first and then t1. Assuming thread t2 goes to the sub() function first, it first locks the mutex and then checks the condition whether the val is 0 or not. As the val is 0 initially, the predicate returns false and as soon as it returns false, it releases the mutex and waits for the condition to be true i.e., val!=0. Now as the mutex is released, addition is performed in the add() function and after that notify_one() gets executed which notifies the waiting thread which in turn tries to get the lock and again checks the condition. This way the process continues.

One of the best use case of condition variable is Producer-Consumer Problem.

3. Promise and Future

The std::future and std::promise are used to return the data from a task executed on the other thread. The std::promise is used to sent the data and the std::future is used to receive the data on the main process. The std::future get() method can be used to retrieve the data returned by the process and is able to hold the current process till the value is returned.

This method is generally preferred of over the condition variable when we only want the task to be executed once.

Example

C++
// C++ program to illustrate the use of std::future and // std::promise in thread synchronization. #include <future> #include <iostream> #include <thread> using namespace std;  // callable void EvenNosFind(promise<int>&& EvenPromise, int begin,                  int end) {     int evenNo = 0;     for (int i = begin; i <= end; i++) {         if (i % 2 == 0) {             evenNo += 1;         }     }     EvenPromise.set_value(evenNo); }  // driver code int main() {     int begin = 0, end = 1000;     promise<int> evenNo;     future<int> evenFuture = evenNo.get_future();     cout << "My thread is created !!!" << endl;     thread t1(EvenNosFind, move(evenNo), begin, end);     cout << "Waiting..........." << endl;      // detting the data     cout << "The no. of even numbers are : "          << evenFuture.get() << endl;     t1.join();     return 0; } 


Output

My thread is created !!!
Waiting...........
The no. of even numbers are : 501

Here, in the above program, we try to find the number of even numbers in the given range. We first create a promise object and then we create a future object from that promise object. We send the promise object to the thread and then once we are ready with the value (after the function has been executed) ,we set the promise object. Then we create a future object from that promise. Finally we get the output from the future object to get our answer.

Conclusion

Thread Synchronization is necessary in the cases when we have multiple threads working on the shared data(critical section) so that the behaviour is defined. We have seen few common method of thread synchronization in C++. Although, it can be done manually using naive and bruteforce methods like (continuously updated some flag when done when done working on the shared data), the above discussed method provides more refined and tested ways of thread synchronization in C++.


Next Article
Thread Synchronization in C++

S

sulagnakundu
Improve
Article Tags :
  • C++
  • Geeks Premier League
  • cpp-multithreading
  • Geeks Premier League 2023
Practice Tags :
  • CPP

Similar Reads

    Thread Pool in C++
    The Thread Pool in C++ is used to manage and efficiently resort to a group (or pool) of threads. Instead of creating threads again and again for each task and then later destroying them, what a thread pool does is it maintains a set of pre-created threads now these threads can be reused again to do
    6 min read
    thread_local Storage in C++ 11
    Thread local storage (TLS) is a feature introduced in C++ 11 that allows each thread in a multi-threaded program to have its own separate instance of a variable. In simple words, we can say that each thread can have its own independent instance of a variable. Each thread can access and modify its ow
    3 min read
    Multithreading in C++
    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. Multith
    5 min read
    Multithreading in C
    A thread is a single sequence stream within a process. Because threads have some of the properties of processes, they are sometimes called lightweight processes. But unlike processes, threads are not independent from each other unlike processes. They share with other threads their code section, data
    9 min read
    Thread hardware_concurrency() function in C++
    Thread::hardware_concurrency is an in-built function in C++ std::thread. It is an observer function which means it observes a state and then returns the corresponding output. This function returns the number of concurrent threads supported by the available hardware implementation. This value might n
    1 min read
geeksforgeeks-footer-logo
Corporate & Communications Address:
A-143, 7th Floor, Sovereign Corporate Tower, Sector- 136, Noida, Uttar Pradesh (201305)
Registered Address:
K 061, Tower K, Gulshan Vivante Apartment, Sector 137, Noida, Gautam Buddh Nagar, Uttar Pradesh, 201305
GFG App on Play Store GFG App on App Store
Advertise with us
  • Company
  • About Us
  • Legal
  • Privacy Policy
  • In Media
  • Contact Us
  • Advertise with us
  • GFG Corporate Solution
  • Placement Training Program
  • Languages
  • Python
  • Java
  • C++
  • PHP
  • GoLang
  • SQL
  • R Language
  • Android Tutorial
  • Tutorials Archive
  • DSA
  • Data Structures
  • Algorithms
  • DSA for Beginners
  • Basic DSA Problems
  • DSA Roadmap
  • Top 100 DSA Interview Problems
  • DSA Roadmap by Sandeep Jain
  • All Cheat Sheets
  • Data Science & ML
  • Data Science With Python
  • Data Science For Beginner
  • Machine Learning
  • ML Maths
  • Data Visualisation
  • Pandas
  • NumPy
  • NLP
  • Deep Learning
  • Web Technologies
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • ReactJS
  • NextJS
  • Bootstrap
  • Web Design
  • Python Tutorial
  • Python Programming Examples
  • Python Projects
  • Python Tkinter
  • Python Web Scraping
  • OpenCV Tutorial
  • Python Interview Question
  • Django
  • Computer Science
  • Operating Systems
  • Computer Network
  • Database Management System
  • Software Engineering
  • Digital Logic Design
  • Engineering Maths
  • Software Development
  • Software Testing
  • DevOps
  • Git
  • Linux
  • AWS
  • Docker
  • Kubernetes
  • Azure
  • GCP
  • DevOps Roadmap
  • System Design
  • High Level Design
  • Low Level Design
  • UML Diagrams
  • Interview Guide
  • Design Patterns
  • OOAD
  • System Design Bootcamp
  • Interview Questions
  • Inteview Preparation
  • Competitive Programming
  • Top DS or Algo for CP
  • Company-Wise Recruitment Process
  • Company-Wise Preparation
  • Aptitude Preparation
  • Puzzles
  • School Subjects
  • Mathematics
  • Physics
  • Chemistry
  • Biology
  • Social Science
  • English Grammar
  • Commerce
  • World GK
  • GeeksforGeeks Videos
  • DSA
  • Python
  • Java
  • C++
  • Web Development
  • Data Science
  • CS Subjects
@GeeksforGeeks, Sanchhaya Education Private Limited, All rights reserved
We use cookies to ensure you have the best browsing experience on our website. By using our site, you acknowledge that you have read and understood our Cookie Policy & Privacy Policy
Lightbox
Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
geeksforgeeks-suggest-icon
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.
geeksforgeeks-improvement-icon
Suggest Changes
min 4 words, max Words Limit:1000

Thank You!

Your suggestions are valuable to us.

What kind of Experience do you want to share?

Interview Experiences
Admission Experiences
Career Journeys
Work Experiences
Campus Experiences
Competitive Exam Experiences