📘 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
- Use lock-free programming for high-performance concurrent code
- Implement thread pools for efficient task execution
- Design concurrent data structures for thread safety
- Apply advanced synchronization for complex coordination
- 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