Skip to content

C++ Concurrent Programming

Overview

C++11 introduced built-in support for multithreading, making concurrent programming more accessible and standardized.

std::thread

Basic Thread Creation

cpp
#include <iostream>
#include <thread>
#include <chrono>

void helloFunction() {
    std::cout << "Hello from thread!" << std::endl;
}

void countFunction(int id, int n) {
    for (int i = 0; i < n; i++) {
        std::cout << "Thread " << id << ": " << i << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

int main() {
    // Create and start a thread
    std::thread thread1(helloFunction);
    
    // Create thread with parameters
    std::thread thread2(countFunction, 1, 5);
    std::thread thread3(countFunction, 2, 5);
    
    // Wait for threads to complete
    thread1.join();
    thread2.join();
    thread3.join();
    
    std::cout << "All threads completed!" << std::endl;
    
    return 0;
}

Lambda Functions with Threads

cpp
#include <iostream>
#include <thread>
#include <vector>

int main() {
    std::vector<std::thread> threads;
    
    // Create multiple threads using lambdas
    for (int i = 0; i < 5; i++) {
        threads.emplace_back([i]() {
            std::cout << "Thread " << i << " is running!" << std::endl;
        });
    }
    
    // Wait for all threads to complete
    for (auto& thread : threads) {
        thread.join();
    }
    
    std::cout << "All threads completed!" << std::endl;
    
    return 0;
}

std::mutex

Mutual Exclusion

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

std::mutex mtx;
int shared_counter = 0;

void incrementCounter(int id) {
    for (int i = 0; i < 1000; i++) {
        // Lock the mutex before accessing shared data
        std::lock_guard<std::mutex> lock(mtx);
        shared_counter++;
        // Mutex is automatically unlocked when lock goes out of scope
    }
}

int main() {
    std::thread thread1(incrementCounter, 1);
    std::thread thread2(incrementCounter, 2);
    
    thread1.join();
    thread2.join();
    
    std::cout << "Final counter value: " << shared_counter << std::endl;
    
    return 0;
}

Manual Lock Management

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

std::mutex mtx;
bool data_ready = false;

void producer() {
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << "Producer: Producing data..." << std::endl;
    data_ready = true;
}

void consumer() {
    while (true) {
        mtx.lock();
        if (data_ready) {
            std::cout << "Consumer: Consuming data!" << std::endl;
            data_ready = false;
            mtx.unlock();
            break;
        }
        mtx.unlock();
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

int main() {
    std::thread producer_thread(producer);
    std::thread consumer_thread(consumer);
    
    producer_thread.join();
    consumer_thread.join();
    
    return 0;
}

std::condition_variable

Thread Synchronization

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

std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;
bool finished = false;

void producer() {
    for (int i = 1; i <= 5; i++) {
        {
            std::lock_guard<std::mutex> lock(mtx);
            data_queue.push(i);
            std::cout << "Producer: Produced " << i << std::endl;
        }
        cv.notify_one();  // Notify one waiting thread
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    
    {
        std::lock_guard<std::mutex> lock(mtx);
        finished = true;
    }
    cv.notify_all();  // Notify all waiting threads
}

void consumer(int id) {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return !data_queue.empty() || finished; });
        
        if (finished && data_queue.empty()) {
            break;
        }
        
        int value = data_queue.front();
        data_queue.pop();
        lock.unlock();
        
        std::cout << "Consumer " << id << ": Consumed " << value << std::endl;
    }
}

int main() {
    std::thread producer_thread(producer);
    std::thread consumer_thread1(consumer, 1);
    std::thread consumer_thread2(consumer, 2);
    
    producer_thread.join();
    consumer_thread1.join();
    consumer_thread2.join();
    
    std::cout << "All threads completed!" << std::endl;
    
    return 0;
}

std::atomic

Atomic Operations

cpp
#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> atomic_counter(0);

void incrementAtomic() {
    for (int i = 0; i < 1000; i++) {
        atomic_counter++;  // Atomic operation
    }
}

int main() {
    std::thread thread1(incrementAtomic);
    std::thread thread2(incrementAtomic);
    
    thread1.join();
    thread2.join();
    
    std::cout << "Final atomic counter: " << atomic_counter << std::endl;
    
    // Atomic operations with memory ordering
    std::atomic<bool> flag(false);
    
    std::thread setter([&flag]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        flag.store(true, std::memory_order_release);
    });
    
    std::thread waiter([&flag]() {
        while (!flag.load(std::memory_order_acquire)) {
            // Busy wait
        }
        std::cout << "Flag is now true!" << std::endl;
    });
    
    setter.join();
    waiter.join();
    
    return 0;
}

std::future and std::promise

Asynchronous Programming

cpp
#include <iostream>
#include <future>
#include <chrono>

int calculateSum(int a, int b) {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return a + b;
}

int main() {
    // Launch async task
    std::future<int> result = std::async(std::launch::async, calculateSum, 10, 20);
    
    std::cout << "Task started, waiting for result..." << std::endl;
    
    // Do other work while waiting
    std::cout << "Doing other work..." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    
    // Get the result (blocks if not ready)
    int sum = result.get();
    std::cout << "Result: " << sum << std::endl;
    
    return 0;
}

Using std::promise

cpp
#include <iostream>
#include <future>
#include <thread>

void setData(std::promise<int> prom) {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    prom.set_value(42);  // Set the value
}

int main() {
    std::promise<int> prom;
    std::future<int> fut = prom.get_future();
    
    std::thread thread(setData, std::move(prom));
    
    std::cout << "Waiting for data..." << std::endl;
    int value = fut.get();  // Wait for and get the value
    std::cout << "Received value: " << value << std::endl;
    
    thread.join();
    
    return 0;
}

Content is for learning and research only.