Concurrency in programming refers to the ability of a program to execute multiple tasks simultaneously. In C++, concurrency is achieved through features like threads, mutexes, condition variables, and atomic operations. Understanding concurrency is crucial for developing efficient and responsive applications, especially in scenarios where tasks can be executed concurrently to improve performance.
thread
class for creating and managing threads.A thread is a sequence of instructions that can execute independently of other threads within the same process. In C++, threads are managed using the <thread>
header.
#include
#include
// Function to be executed by the thread
void threadFunction() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
// Create a thread and pass the function to execute
std::thread t(threadFunction);
// Join the thread with the main thread
t.join();
return 0;
}
// output //
Hello from thread!
threadFunction()
that will be executed by the thread.main()
, we create a thread t
and pass threadFunction
as an argument to execute.join()
function is called to wait for the thread to finish execution before continuing with the main thread.Mutexes (short for mutual exclusion) are synchronization primitives used to protect shared resources from being accessed simultaneously by multiple threads. In C++, mutexes are provided by the <mutex>
header.
#include
#include
#include
std::mutex mtx;
// Function to be executed by the thread
void threadFunction() {
mtx.lock(); // Acquire the mutex
std::cout << "Hello from thread!" << std::endl;
mtx.unlock(); // Release the mutex
}
int main() {
std::thread t(threadFunction);
mtx.lock(); // Acquire the mutex before printing
std::cout << "Hello from main!" << std::endl;
mtx.unlock(); // Release the mutex after printing
t.join();
return 0;
}
// output //
Hello from main!
Hello from thread!
mtx
to protect access to the shared std::cout
object.threadFunction()
, the thread acquires the mutex before printing, ensuring exclusive access to the std::cout
object.main()
, the main thread acquires the mutex before printing, preventing interleaved output with the thread.Condition variables are synchronization primitives used to coordinate the execution of multiple threads. They allow threads to wait for a certain condition to become true before proceeding.
#include
#include
#include
#include
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
// Function to be executed by the thread
void threadFunction() {
std::unique_lock lck(mtx);
while (!ready) {
cv.wait(lck);
}
std::cout << "Hello from thread!" << std::endl;
}
int main() {
std::thread t(threadFunction);
{
std::lock_guard lck(mtx);
ready = true;
}
cv.notify_one();
t.join();
return 0;
}
// output //
Hello from thread!
cv
along with a mutex mtx
to protect access to the shared variable ready
.threadFunction()
, the thread waits on the condition variable cv
until ready
becomes true.main()
, the main thread sets ready
to true and notifies the waiting thread using notify_one()
.A race condition occurs when the outcome of a program depends on the relative timing of operations executed by multiple threads. It can lead to unpredictable behavior and bugs that are difficult to reproduce.
#include
#include
int counter = 0;
// Function to be executed by the thread
void incrementCounter() {
for (int i = 0; i < 1000; ++i) {
counter++; // Race condition: multiple threads accessing shared variable
}
}
int main() {
std::thread t1(incrementCounter);
std::thread t2(incrementCounter);
t1.join();
t2.join();
std::cout << "Counter value: " << counter << std::endl;
return 0;
}
// output //
Counter value: 1400
t1
and t2
increment the shared variable counter
concurrently.counter
simultaneously, leading to unpredictable results.counter
depends on the interleaving of operations by the two threads.A deadlock occurs when two or more threads are unable to proceed because each is waiting for the other to release a resource, resulting in a cyclic dependency.
#include
#include
#include
std::mutex mtx1, mtx2;
// Function to be executed by the first thread
void threadFunction1() {
mtx1.lock();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
mtx2.lock();
std::cout << "Thread 1 acquired both mutexes." << std::endl;
mtx1.unlock();
mtx2.unlock();
}
// Function to be executed by the second thread
void threadFunction2() {
mtx2.lock();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
mtx1.lock(); // Deadlock: second thread waiting for mtx1, which is held by first thread
std::cout << "Thread 2 acquired both mutexes." << std::endl;
mtx2.unlock();
mtx1.unlock();
}
int main() {
std::thread t1(threadFunction1);
std::thread t2(threadFunction2);
t1.join();
t2.join();
return 0;
}
// output //
[No output, program hangs indefinitely]
t1
and t2
attempt to acquire two mutexes mtx1
and mtx2
, but in opposite order.t1
holds mtx1
and waits for mtx2
, while t2
holds mtx2
and waits for mtx1
.async
and obtain a future object that holds the result when it becomes available.sort
, transform
) that can leverage multiple cores to improve performance on suitable tasks.Avoid Global Variables: Minimize the use of global variables accessed by multiple threads to reduce the risk of race conditions.
Use Mutexes Carefully: Ensure that critical sections of code are properly protected by mutexes to prevent race conditions.
Avoid Deadlocks: Be cautious when acquiring multiple mutexes to avoid potential deadlocks. Use techniques like lock hierarchy to establish a consistent order for acquiring mutexes.
Concurrency in C++ offers powerful capabilities for developing responsive and efficient applications. By understanding and applying concepts like threads, mutexes, and condition variables, you can harness the benefits of concurrent programming while mitigating risks such as race conditions and deadlocks. However, concurrency introduces complexities that require careful consideration and adherence to best practices. With the knowledge gained from this chapter, you're well-equipped to leverage concurrency effectively in your C++ projects, enhancing their performance and scalability.Happy coding !❤️