liveBook · Manning

What you will learn in C++ Concurrency in Action, Second Edition

by Anthony Williams

Chapter by chapter

Chapter 1: Chapter 1. Hello, world of concurrency in C++!

The chapter introduction explains why C++11’s standardized multithreading support mattered and previews the chapter’s path from basic concepts to a simple concurrent program.

1.1 What is concurrency? · 1.1.1 Concurrency in computer systems · 1.1.2 Approaches to concurrency · 1.1.3 Concurrency vs. parallelism · 1.2 Why use concurrency? · 1.2.1 Using concurrency for separation of concerns · 1.2.2 Using concurrency for performance: task and data parallelism · 1.2.3 When not to use concurrency · 1.3 Concurrency and multithreading in C++ · 1.3.1 History of multithreading in C++ · 1.3.2 Concurrency support in the C++11 standard · 1.3.3 More support for concurrency and parallelism in C++14 and C++17 · 1.3.4 Efficiency in the C++ Thread Library · 1.3.5 Platform-specific facilities · 1.4 Getting started · 1.4.1 Hello, Concurrent World · 1.5 Summary

What you learn in chapter 1 →

Chapter 2: Chapter 2. Managing threads

The chapter introduces std::thread as the main way to manage threads and previews the thread-management tasks it will cover.

2.1 Basic thread management · 2.1.1 Launching a thread · 2.1.2 Waiting for a thread to complete · 2.1.3 Waiting in exceptional circumstances · 2.1.4 Running threads in the background · 2.2 Passing arguments to a thread function · 2.3 Transferring ownership of a thread · 2.4 Choosing the number of threads at runtime · 2.5 Identifying threads · 2.6 Summary

What you learn in chapter 2 →

Chapter 3: Chapter 3. Sharing data between threads

The chapter introduces the benefits and risks of sharing data between threads and previews ways to protect it.

3.1 Problems with sharing data between threads · 3.1.1 Race conditions · 3.1.2 Avoiding problematic race conditions · 3.2 Protecting shared data with mutexes · 3.2.1 Using mutexes in C++ · 3.2.2 Structuring code for protecting shared data · 3.2.3 Spotting race conditions inherent in interfaces · 3.2.4 Deadlock: the problem and a solution · 3.2.5 Further guidelines for avoiding deadlock · 3.2.6 Flexible locking with std::unique_lock · 3.2.7 Transferring mutex ownership between scopes · 3.2.8 Locking at an appropriate granularity · 3.3 Alternative facilities for protecting shared data · 3.3.1 Protecting shared data during initialization · 3.3.2 Protecting rarely updated data structures · 3.3.3 Recursive locking · 3.4 Summary

What you learn in chapter 3 →

Chapter 4: Chapter 4. Synchronizing concurrent operations

The chapter introduces waiting for other threads’ actions and surveys the C++ facilities used to synchronize them.

4.1 Waiting for an event or other condition · 4.1.1 Waiting for a condition with condition variables · 4.1.2 Building a thread-safe queue with condition variables · 4.2 Waiting for one-off events with futures · 4.2.1 Returning values from background tasks · 4.2.2 Associating a task with a future · 4.2.3 Making (std::)promises · 4.2.4 Saving an exception for the future · 4.2.5 Waiting from multiple threads · 4.3 Waiting with a time limit · 4.3.1 Clocks · 4.3.2 Durations · 4.3.3 Time points · 4.3.4 Functions that accept timeouts · 4.4 Using synchronization of operations to simplify code · 4.4.1 Functional programming with futures · 4.4.2 Synchronizing operations with message passing · 4.4.3 Continuation-style concurrency with the Concurrency TS · 4.4.4 Chaining continuations · 4.4.5 Waiting for more than one future · 4.4.6 Waiting for the first future in a set with when_any · 4.4.7 Latches and barriers in the Concurrency TS · 4.4.8 A basic latch type: std::experimental::latch · 4.4.9 std::experimental::barrier: a basic barrier · 4.4.10 std::experimental::flex_barrier—std::experimental::barrier’s flexible friend · 4.5 Summary

What you learn in chapter 4 →

Chapter 5: Chapter 5. The C++ memory model and operations on atomic types

This introduction explains why C++ needs a multithreading-aware memory model, when programmers need its details, and how the chapter will approach atomic synchronization.

5.1 Memory model basics · 5.1.1 Objects and memory locations · 5.1.2 Objects, memory locations, and concurrency · 5.1.3 Modification orders · 5.2 Atomic operations and types in C++ · 5.2.1 The standard atomic types · 5.2.2 Operations on std::atomic_flag · 5.2.3 Operations on std::atomic<bool> · 5.2.4 Operations on std::atomic<T*>: pointer arithmetic · 5.2.5 Operations on standard atomic integral types · 5.2.6 The std::atomic<> primary class template · 5.2.7 Free functions for atomic operations · 5.3 Synchronizing operations and enforcing ordering · 5.3.1 The synchronizes-with relationship · 5.3.2 The happens-before relationship · 5.3.3 Memory ordering for atomic operations · 5.3.4 Release sequences and synchronizes-with · 5.3.5 Fences · 5.3.6 Ordering non-atomic operations with atomics · 5.3.7 Ordering non-atomic operations · 5.4 Summary

What you learn in chapter 5 →

Chapter 6: Chapter 6. Designing lock-based concurrent data structures

The chapter introduces why data structures need deliberate design for concurrent access and previews lock-based examples before a later chapter turns to lock-free designs.

6.1 What does it mean to design for concurrency? · 6.1.1 Guidelines for designing data structures for concurrency · 6.2 Lock-based concurrent data structures · 6.2.1 A thread-safe stack using locks · 6.2.2 A thread-safe queue using locks and condition variables · 6.2.3 A thread-safe queue using fine-grained locks and condition variables · 6.3 Designing more complex lock-based data structures · 6.3.1 Writing a thread-safe lookup table using locks · 6.3.2 Writing a thread-safe list using locks · 6.4 Summary

What you learn in chapter 6 →

Chapter 7: Chapter 7. Designing lock-free concurrent data structures

The introduction motivates lock-free data structures, identifies atomic memory ordering as their foundation, and previews the chapter’s definitions, examples, memory-management techniques, and guidelines.

7.1 Definitions and consequences · 7.1.1 Types of nonblocking data structures · 7.1.2 Lock-free data structures · 7.1.3 Wait-free data structures · 7.1.4 The pros and cons of lock-free data structures · 7.2 Examples of lock-free data structures · 7.2.1 Writing a thread-safe stack without locks · 7.2.2 Stopping those pesky leaks: managing memory in lock-free data structures · 7.2.3 Detecting nodes that can’t be reclaimed using hazard pointers · 7.2.4 Detecting nodes in use with reference counting · 7.2.5 Applying the memory model to the lock-free stack · 7.2.6 Writing a thread-safe queue without locks · 7.3 Guidelines for writing lock-free data structures · 7.3.1 Guideline: use std::memory_order_seq_cst for prototyping · 7.3.2 Guideline: use a lock-free memory reclamation scheme · 7.3.3 Guideline: watch out for the ABA problem · 7.3.4 Guideline: identify busy-wait loops and help the other thread · 7.4 Summary

What you learn in chapter 7 →

Chapter 8: Chapter 8. Designing concurrent code

The introduction shifts from building thread-safe data structures to designing useful concurrent code, outlining the decisions and tradeoffs the chapter will examine.

8.1 Techniques for dividing work between threads · 8.1.1 Dividing data between threads before processing begins · 8.1.2 Dividing data recursively · 8.1.3 Dividing work by task type · 8.2 Factors affecting the performance of concurrent code · 8.2.1 How many processors? · 8.2.2 Data contention and cache ping-pong · 8.2.3 False sharing · 8.2.4 How close is your data? · 8.2.5 Oversubscription and excessive task switching · 8.3 Designing data structures for multithreaded performance · 8.3.1 Dividing array elements for complex operations · 8.3.2 Data access patterns in other data structures · 8.4 Additional considerations when designing for concurrency · 8.4.1 Exception safety in parallel algorithms · 8.4.2 Scalability and Amdahl’s law · 8.4.3 Hiding latency with multiple threads · 8.4.4 Improving responsiveness with concurrency · 8.5 Designing concurrent code in practice · 8.5.1 A parallel implementation of std::for_each · 8.5.2 A parallel implementation of std::find · 8.5.3 A parallel implementation of std::partial_sum · 8.6 Summary

What you learn in chapter 8 →

Chapter 9: Chapter 9. Advanced thread management

The introduction motivates automatic management of threads and tasks, explains why threads sometimes need to stop early, and previews the chapter’s two topics.

9.1 Thread pools · 9.1.1 The simplest possible thread pool · 9.1.2 Waiting for tasks submitted to a thread pool · 9.1.3 Tasks that wait for other tasks · 9.1.4 Avoiding contention on the work queue · 9.1.5 Work stealing · 9.2 Interrupting threads · 9.2.1 Launching and interrupting another thread · 9.2.2 Detecting that a thread has been interrupted · 9.2.3 Interrupting a condition variable wait · 9.2.4 Interrupting a wait on std::condition_variable_any · 9.2.5 Interrupting other blocking calls · 9.2.6 Handling interruptions · 9.2.7 Interrupting background tasks on application exit · 9.3 Summary

What you learn in chapter 9 →

Chapter 10: Chapter 10. Parallel algorithms

The introduction connects earlier work on concurrent code and thread pools to the chapter’s focus on C++17 standard parallel algorithms.

10.1 Parallelizing the standard library algorithms · 10.2 Execution policies · 10.2.1 General effects of specifying an execution policy · 10.2.2 std::execution::sequenced_policy · 10.2.3 std::execution::parallel_policy · 10.2.4 std::execution::parallel_unsequenced_policy · 10.3 The parallel algorithms from the C++ Standard Library · 10.3.1 Examples of using parallel algorithms · 10.3.2 Counting visits · 10.4 Summary

What you learn in chapter 10 →

Chapter 11: Chapter 11. Testing and debugging multithreaded applications

The chapter introduces the difficulty of testing and debugging concurrent code and outlines an issues-first approach to finding and removing bugs.

11.1 Types of concurrency-related bugs · 11.1.1 Unwanted blocking · 11.1.2 Race conditions · 11.2 Techniques for locating concurrency-related bugs · 11.2.1 Reviewing code to locate potential bugs · 11.2.2 Locating concurrency-related bugs by testing · 11.2.3 Designing for testability · 11.2.4 Multithreaded testing techniques · 11.2.5 Structuring multithreaded test code · 11.2.6 Testing the performance of multithreaded code · 11.3 Summary

What you learn in chapter 11 →

Concepts explained in this book

These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.