📘 Learning Objectives

After completing this chapter, you will: - Master advanced concurrency patterns and techniques - Understand lock-free programming and atomic operations - Learn about thread pools and task scheduling - Master concurrent data structures - Understand performance optimization in concurrent programs

🎯 Key Concepts

1. Lock-Free Programming

  • Atomic operations: Lock-free atomic operations
  • Memory ordering: Memory consistency models
  • Compare-and-swap: CAS operations
  • Lock-free data structures: Lock-free containers
  • ABA problem: ABA problem prevention

2. Thread Pools and Task Scheduling

  • Thread pools: Managed thread execution
  • Task queues: Work distribution
  • Load balancing: Work load distribution
  • Task scheduling: Priority-based scheduling
  • Work stealing: Work stealing algorithms

3. Concurrent Data Structures

  • Concurrent containers: Thread-safe containers
  • Lock-free containers: Lock-free data structures
  • Producer-consumer: Producer-consumer patterns
  • Readers-writers: Readers-writers patterns
  • Transactional memory: Software transactional memory

4. Advanced Synchronization

  • Barriers: Synchronization barriers
  • Latches: Countdown latches
  • Semaphores: Counting semaphores
  • Futures and promises: Asynchronous programming
  • Coroutines: C++20 coroutines

5. Performance and Scalability

  • Concurrency performance: Performance optimization
  • Scalability patterns: Scalable concurrent design
  • Memory model: C++ memory model
  • Cache optimization: Cache-friendly concurrent code
  • Profiling: Concurrent program profiling

🧩 Practice Exercises

Exercise 42.1: Lock-Free Programming

Implement lock-free data structures.

Exercise 42.2: Thread Pools

Create and use thread pools for parallel execution.

Exercise 42.3: Concurrent Data Structures

Implement thread-safe containers.

Exercise 42.4: Performance Optimization

Optimize concurrent programs for performance.

💻 Code Examples

Lock-Free Programming

#include <iostream>
#include <atomic>
#include <thread>
#include <vector>

class LockFreeCounter {
private:
    std::atomic<int> count{0};
public:
    void increment() {
        count.fetch_add(1, std::memory_order_relaxed);
    }

    int get() const {
        return count.load(std::memory_order_relaxed);
    }
};

int main() {
    LockFreeCounter counter;
    std::vector<std::thread> threads;

    // Create multiple threads
    for (int i = 0; i < 4; ++i) {
        threads.emplace_back([&counter]() {
            for (int j = 0; j < 1000; ++j) {
                counter.increment();
            }
        });
    }

    // Wait for all threads
    for (auto& t : threads) {
        t.join();
    }

    std::cout << "Final count: " << counter.get() << std::endl;
    return 0;
}

Thread Pool

#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>

class ThreadPool {
private:
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop;

public:
    ThreadPool(size_t num_threads) : stop(false) {
        for (size_t i = 0; i < num_threads; ++i) {
            workers.emplace_back([this] {
                while (true) {
                    std::function<void()> task;

                    {
                        std::unique_lock<std::mutex> lock(queue_mutex);
                        condition.wait(lock, [this] { return stop || !tasks.empty(); });

                        if (stop && tasks.empty()) return;

                        task = tasks.front();
                        tasks.pop();
                    }

                    task();
                }
            });
        }
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            stop = true;
        }

        condition.notify_all();

        for (std::thread& worker : workers) {
            worker.join();
        }
    }

    template<typename F>
    auto enqueue(F&& f) -> std::future<decltype(f())> {
        using ReturnType = decltype(f());

        auto task = std::make_shared<std::packaged_task<ReturnType()>>(
            std::forward<F>(f)
        );

        std::future<ReturnType> result = task->get_future();

        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            tasks.emplace([task] { (*task)(); });
        }

        condition.notify_one();
        return result;
    }
};

int main() {
    ThreadPool pool(4);

    // Submit tasks
    std::vector<std::future<int>> results;

    for (int i = 0; i < 8; ++i) {
        results.emplace_back(
            pool.enqueue([i]() -> int {
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                return i * i;
            })
        );
    }

    // Collect results
    for (auto& result : results) {
        std::cout << "Result: " << result.get() << std::endl;
    }

    return 0;
}

🎓 Key Takeaways

  1. Use lock-free programming for high-performance concurrent code
  2. Implement thread pools for efficient task execution
  3. Design concurrent data structures for thread safety
  4. Apply advanced synchronization for complex coordination
  5. Optimize for performance in concurrent programs

🔗 Next Steps

After mastering advanced concurrency, proceed to Chapter 43 to learn about the C Standard Library.

📚 Additional Resources

  • C++ Reference: Concurrency
  • C++ Core Guidelines: Concurrency
  • Practice with concurrent programming patterns