Concurrency refers to the ability to process multiple tasks or threads at the same time. It is used to improve the program's performance and response time. In this article, we will discuss how concurrency is achieved in C++ and what are its benefits.
Concurrency in C++
In C++, the support for concurrency was first added in C++ 11 to improve the performance of the program and enable multitasking. The components such as thread, mutex, memory model, and various synchronization primitives were added as the part of Concurrency Support Library.
Although concurrency provides multitasking, it doesn't mean that the tasks are executed simultaneously in different processing units. Instead, it works by task switching i.e. doing some task for a small time, then moving to the other tasks, and then coming back again to the first task. It will keep doing it till both of the tasks are done.
In C++, we can achieve concurrency using threads:
Threads in C++
Threads are the basic unit of multitasking. The concurrent execution of the tasks is done by creating multiple threads in a multithreaded environment. The C++ provides a <thread> library for creating and managing threads.
To know more about threads in C++, refer to the article - Multithreading in C++
Errors and Risks Associated with Concurrency
Concurrent multithreading applications need to be carefully designed as it is prone to many errors leading to undefined behaviour. Some of these errors are:
1. Deadlocks
Deadlock refers to the situation where the two or more threads are blocked the forever waiting for the each other. The careful synchronization is essential to the prevent deadlocks.
2. Race Conditions
Race conditions happens when two or more the threads access shared data concurrently leading to the undefined behaviour.
3. Starvation
Starvation is the condition where a thread is unable to the gain regular access to the shared resources.
The above problems can be avoided by proper synchronization between the threads.
Thread Synchronization in C++
Thread synchronization can be done using the following components provided in the C++:
1. Mutex and Locks
The Mutual Exclusion and Locks are used to the protect shared resources. Ensures that only one thread accesses critical sections at a time. C++ have <mutex> header file which contains the std::mutex classes.
To know more about mutex in C++, refer to the article - Mutex in C++
2. Condition Variables
Condition Variables are used for thread synchronization by acting as a flag that notifies the threads when the shared resources are free. It provides a wait-free synchronization in contrast to what mutex and locks do. C++ have <condition_variable> header that contains the condition_variable object.
To know more about condition variable in C++. refer to the article - Condition Variables in C++.
3. Futures and Promises
The <future> and <promise> are used for the asynchronous task execution. This method is only viable when the thread tasks are independent of each other.
4. Semaphores
It is also a synchronization primitive that counts the number of threads accessing the shared resource. If this count exceeds the number of access available, the semaphore will block the access till the count is freed.
Example: Concurrent C++ Program
C++
// C++ Program to illustrate the use of multiple thread
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
using namespace std;
// shared resource that will be updated
int sum = 0;
// mutex lock for synchronization (althout application can
// work just fine without it in this case, it is still used
// for demonstration)
mutex lck;
// function to get sum of the vector elements in the given
// range
void getSum(const vector<int>& v, int start, int end)
{
// a predefined wrapper over mutex lock
lock_guard<mutex> mu(lck);
// performing operation
for (int i = start; i <= end; i++) {
sum += v[i];
}
// mu object will automatically release the mutex lock
// lck when destroyed
}
// driver code
int main()
{
// vector with 10 elements
vector<int> v
= { 2, 4654, 321, 65, 32, 165, 432, 2, 16, 54 };
// finding mid point
int mid = v.size() / 2;
// creating two threads
// one thread to add first half elements
thread t1(getSum, v, 0, mid);
// other thread to add second half elements
thread t2(getSum, v, mid + 1, v.size() - 1);
// waiting for threads to finish
t1.join();
t2.join();
cout << "Array Elements: ";
for (auto i : v) {
cout << i << " ";
}
cout << endl;
// printing sum
cout << "Sum: " << sum;
return 0;
}
Output
Array Elements: 2 4654 321 65 32 165 432 2 16 54
Sum: 6048
Concurrency vs Parallelism
The terms concurrency and parallelism are often told as same but there is some difference between them. The below table lists the major differences between the concurrency and parallelism:
Characteristics | Concurrency | Parallelism |
---|
Definition | Processing multiple tasks in the overlapping time intervals | Simultaneous execution of the multiple tasks on different threads. |
---|
Focus | Making progress on more than one task at time. | Performing multiple tasks at exactly the same time. |
---|
Processor Usage | Single processor or core at one | Multiple processors or cores at once |
---|
Task Interaction | Tasks may or may not interact with the each other | Tasks often work the independently or communicate |
---|
Use Cases | Suitable and faster for small tasks as it doesn't have overhead due to being in the single core. | Suitable for large tasks for which the thread setup overhead costs is negligible. |
---|
Benefits of Concurrency
The concurrency provides a lot of benefits to the programmer and application:
- Improved Performance: The utilizing multiple CPU cores and executing different parts of your program can improve the performance drastically.
- Responsiveness: The Applications remain responsive and don't freeze while performing intensive operations.
- Resource Utilization: The Efficiently utilize system resources and make the most of the modern multi-core processors.
Similar Reads
Concurrency in Python
Concurrency is one approach to drastically increase the performance of your Python programs. Concurrency allows several processes to be completed concurrently, maximizing the utilization of your system's resources. Concurrency can be achieved in Python by the use of numerous methods and modules, suc
6 min read
Concurrent Lines
Concurrent Lines occur when three or more lines intersect at a single point. This concept is a significant topic within the realm of straight lines. In this article on Concurrent Lines, we will delve into the precise definition of concurrent lines, explore the conditions that lead to concurrent line
10 min read
cout in C++
In C++, cout is an object of the ostream class that is used to display output to the standard output device, usually the monitor. It is associated with the standard C output stream stdout. The insertion operator (<<) is used with cout to insert data into the output stream.Let's take a look at
2 min read
Structured Concurrency in Java
Structured concurrency organizes concurrent processes in a controlled way to ease concurrent execution. It prevents race situations, deadlocks, and orphaned jobs. Structured concurrency may be implemented in Java utilizing libraries, frameworks, or experimental initiatives like Project Loom. Structu
2 min read
Tornado-Coroutines and concurrency
Concurrency is a fundamental aspect of modern programming, especially in web development where handling multiple tasks simultaneously is crucial for performance and responsiveness. Tornado, a Python web framework and asynchronous networking library, excels in this area with its powerful coroutine an
6 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
How to handle concurrency in Node.js ?
Node.js is an open-source, cross-platform runtime environment built on Chrome's V8 Engine. It is used to develop highly scalable backend as well as server-side applications. Node.js uses a single-threaded event loop architecture. It is also asynchronous in nature. These are the two main reasons why
4 min read
std::future in C++
The C++ Concurrency support library includes the std::future class template, which has been available since C++11. This template is defined in the <future> header and provides a means to access the outcomes of asynchronous operations. What is std::future in C++? In C++, the std::future is a cl
4 min read
Conflicts and Concurrency in Distributed Systems
In distributed systems, where multiple processes operate across different nodes, managing conflicts and concurrency is crucial for maintaining data consistency and system reliability. This article provides an in-depth look at conflicts and concurrency, exploring their impacts and the techniques used
7 min read
Code- Scheduling Constraints
Data dependence analysis is used to determine the order of execution of instructions. It is used to determine the order of execution of instructions because it gives an indication of how much effort will be required for a particular instruction to be executed at any given time. A data-dependent inst
9 min read