» Quick Introduction to C++ » 2. Advanced » 2.4 Concurrency

Concurrency

Concurrency in C++ is typically achieved using threads. Threads are separate flows of execution that run independently within a process. They share the same memory space, allowing them to communicate and coordinate with each other.

Threads

The <thread> header provides classes and functions for working with threads in C++.

#include <iostream>
#include <thread>

// Function to be executed by the thread
void printNumbers(int start, int end) {
    for (int i = start; i <= end; ++i) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
}

int main() {
    // Create two threads and pass the function to be executed by each thread
    std::thread t1(printNumbers, 1, 5);
    std::thread t2(printNumbers, 6, 10);

    // Wait for both threads to finish
    t1.join();
    t2.join();

    return 0;
}

Mutex

A mutex (short for "mutual exclusion") is a synchronization mechanism used in concurrent programming to ensure that only one thread at a time can access a shared resource or a critical section of code.

The purpose of using a mutex is to prevent data corruption and unexpected behavior that can occur when multiple threads attempt to modify shared data simultaneously.

#include <iostream>
#include <thread>
#include <mutex>

// Global variable shared among threads
int sharedData = 0;

// Mutex to protect access to sharedData
std::mutex dataMutex;

// Function to be executed by the thread
void incrementSharedData(int iterations) {
    for (int i = 0; i < iterations; ++i) {
        // Lock the mutex before accessing sharedData
        std::lock_guard<std::mutex> lock(dataMutex);
        
        // Increment sharedData in a thread-safe manner
        sharedData++;
    }
}

int main() {
    // Create two threads and pass the function to be executed by each thread
    std::thread t1(incrementSharedData, 1000000);
    std::thread t2(incrementSharedData, 1000000);

    // Wait for both threads to finish
    t1.join();
    t2.join();

    // Output the final value of sharedData
    std::cout << "Final value of sharedData: " << sharedData << std::endl;

    return 0;
}

To ensure that the increment operation is thread-safe, a std::lock_guard is used to lock the dataMutex before accessing sharedData. This ensures that only one thread can access the shared data at a time, preventing data races.

Condition Variable

A condition variable is a synchronization primitive used for inter-thread communication. It provides a way for threads to block until a certain condition is met, allowing threads to coordinate their activities.

The C++ Standard Library provides the <condition_variable> header for this purpose.

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool dataReady = false;

// Function to be executed by the first thread
void prepareData() {
    // Simulate some work
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    // Lock the mutex and set the condition to true
    {
        std::lock_guard<std::mutex> lock(mtx);
        dataReady = true;
    }

    // Notify waiting thread that data is ready
    cv.notify_one();
}

// Function to be executed by the second thread
void processData() {
    // Lock the mutex
    std::unique_lock<std::mutex> lock(mtx);

    // Wait for the condition to be true
    cv.wait(lock, []{ return dataReady; });

    // Process the data
    std::cout << "Data processing started." << std::endl;

    // Unlock the mutex explicitly (unique_lock provides more flexibility)
    lock.unlock();

    // Continue processing data (out of the critical section)
    std::this_thread::sleep_for(std::chrono::milliseconds(200));

    std::cout << "Data processing completed." << std::endl;
}

int main() {
    // Create two threads and pass the functions to be executed by each thread
    std::thread t1(prepareData);
    std::thread t2(processData);

    // Wait for both threads to finish
    t1.join();
    t2.join();

    return 0;
}

Code Challenge

Write a C++ program that simulates a simple buffer shared between two threads. One thread (Producer) adds items to the buffer, and another thread (Consumer) removes items from the buffer. Use a mutex to ensure thread safety.

Loading...
> code result goes here
Prev
Next