Concurrency with Modern C++: What every professional C++ programmer should know about concurrency

Concurrency with Modern C++: What every professional C++ programmer should know about concurrency

Concurrency with Modern C++: What every professional C++ programmer should know about concurrency
Автор: Grimm Rainer, Jaud-Grimm Beatrix
Дата выхода: 2024
Издательство: Lean Publishing
Количество страниц: 737
Размер файла: 6,6 МБ
Тип файла: PDF
Добавил: codelibs
 Проверить на вирусы

Reader Testimonials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii
Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii
Special Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii
Special Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii
Special Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv
Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv
Run the Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv
How should you read the book? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v
Personal Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v
Acknowledgment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v
About Me . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi
A Quick Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1. Concurrency with Modern C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1 C++11 and C++14: The Foundation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.1 Memory Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.2 Multithreading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 C++17: Parallel Algorithms of the Standard Template Library . . . . . . . . . . . . . 8
1.2.1 Execution Policy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.2 New Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.3 Coroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.4 Case Studies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.4.1 Calculating the Sum of a Vector . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.4.2 The Dining Philosophers Problem by Andre Adrian . . . . . . . . . . . . . . 10
1.4.3 Thread-Safe Initialization of a Singleton . . . . . . . . . . . . . . . . . . . . 10
1.4.4 Ongoing Optimization with CppMem . . . . . . . . . . . . . . . . . . . . . 10
1.4.5 Fast Synchronization of Threads . . . . . . . . . . . . . . . . . . . . . . . . 10
1.5 Variations of Futures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.6 Modification and Generalization of a Generator . . . . . . . . . . . . . . . . . . . . . 11
1.7 Various Job Workflows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.8 The Future of C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.8.1 Executors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.8.2 Extended futures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.8.3 Transactional Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.8.4 Task Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.8.5 Data-Parallel Vector Library . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.9 Patterns and Best Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.9.1 Synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.9.2 Concurrent Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.9.3 Best Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.10 Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.11 Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.12 Time Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.13 CppMem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.14 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
The Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2. Memory Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.1 Basics of the Memory Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.1.1 What is a memory location? . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.1.2 What happens if two threads access the same memory location? . . . . . . . 19
2.2 The Contract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2.1 The Foundation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.2.2 The Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3 Atomics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3.1 Strong versus Weak Memory Model . . . . . . . . . . . . . . . . . . . . . . 23
2.3.2 The Atomic Flag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.3.3 std::atomic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.3.4 All Atomic Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.3.5 Free Atomic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.3.6 std::atomic_ref (C++20) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.4 The Synchronization and Ordering Constraints . . . . . . . . . . . . . . . . . . . . . 67
2.4.1 The Six Variants of Memory Orderings in C++ . . . . . . . . . . . . . . . . 67
2.4.2 Sequential Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.4.3 Acquire-Release Semantic . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
2.4.4 std::memory_order_consume . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
2.4.5 Relaxed Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
2.5 Fences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
2.5.1 std::atomic_thread_fence . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
2.5.2 std::atomic_signal_fence . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
3. Multithreading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.1 The Basic Thread std::thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
3.1.1 Thread Creation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
3.1.2 Thread Lifetime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
3.1.3 Thread Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
3.1.4 Member Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
3.2 The Improved Thread std::jthread (C++20) . . . . . . . . . . . . . . . . . . . . . . . 116
3.2.1 Automatically Joining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
3.2.2 Cooperative Interruption of a std::jthread . . . . . . . . . . . . . . . . . . 119
3.3 Shared Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
3.3.1 Mutexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
3.3.2 Locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
3.3.3 std::lock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
3.3.4 Thread-safe Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
3.4 Thread-Local Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
3.5 Condition Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
3.5.1 The Predicate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
3.5.2 Lost Wakeup and Spurious Wakeup . . . . . . . . . . . . . . . . . . . . . . . 157
3.5.3 The Wait Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
3.6 Cooperative Interruption (C++20) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
3.6.1 std::stop_source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
3.6.2 std::stop_token . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
3.6.3 std::stop_callback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
3.6.4 A General Mechanism to Send Signals . . . . . . . . . . . . . . . . . . . . . 165
3.6.5 Additional Functionality of std::jthread . . . . . . . . . . . . . . . . . . . 168
3.6.6 New wait Overloads for the condition_variable_any . . . . . . . . . . . . . 169
3.7 Semaphores (C++20) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
3.8 Latches and Barriers (C++20) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
3.8.1 std::latch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
3.8.2 std::barrier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
3.9 Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
3.9.1 Tasks versus Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
3.9.2 std::async . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
3.9.3 std::packaged_task . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
3.9.4 std::promise and std::future . . . . . . . . . . . . . . . . . . . . . . . . . 199
3.9.5 std::shared_future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
3.9.6 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
3.9.7 Notifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
3.10 Synchronized Outputstreams (C++20) . . . . . . . . . . . . . . . . . . . . . . . . . . 215
4. Parallel Algorithms of the Standard Template Library . . . . . . . . . . . . . . . . . . . 225
4.1 Execution Policies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
4.1.1 Parallel and Vectorized Execution . . . . . . . . . . . . . . . . . . . . . . . . 228
4.1.2 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
4.1.3 Hazards of Data Races and Deadlocks . . . . . . . . . . . . . . . . . . . . . 231
4.2 Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
4.3 The New Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
4.3.1 More overloads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
4.3.2 The functional Heritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
4.4 Compiler Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
4.4.1 Microsoft Visual Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
4.4.2 GCC Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
4.4.3 Further Implementations of the Parallel STL . . . . . . . . . . . . . . . . . . 242
4.5 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
4.5.1 Microsoft Visual Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
4.5.2 GCC Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
5. Coroutines (C++20) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
5.1 A Generator Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
5.2 Characteristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
5.2.1 Typical Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
5.2.2 Underlying Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
5.2.3 Design Goals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
5.2.4 Becoming a Coroutine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
5.3 The Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
5.3.1 Promise Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
5.3.2 Coroutine Handle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
5.3.3 Coroutine Frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
5.4 Awaitables and Awaiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
5.4.1 Awaitables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
5.4.2 The Concept Awaiter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
5.4.3 std::suspend_always and std::suspend_never . . . . . . . . . . . . . . . . . 257
5.4.4 initial_suspend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
5.4.5 final_suspend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
5.4.6 Awaiter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
5.5 The Workflows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
5.5.1 The Promise Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
5.5.2 The Awaiter Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
5.6 co_return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
5.6.1 A Future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
5.7 co_yield . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
5.7.1 An Infinite Data Stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
5.8 co_await . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
5.8.1 Starting a Job on Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
5.8.2 Thread Synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
5.9 std::generator (C++23) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
6. Case Studies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
6.1 Calculating the Sum of a Vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
6.1.1 Single-Threaded addition of a Vector . . . . . . . . . . . . . . . . . . . . . . 280
6.1.2 Multi-threaded Summation with a Shared Variable . . . . . . . . . . . . . . 286
6.1.3 Thread-Local Summation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
6.1.4 Summation of a Vector: The Conclusion . . . . . . . . . . . . . . . . . . . . 303
6.2 The Dining Philosophers Problem by Andre Adrian . . . . . . . . . . . . . . . . . . . 305
6.2.1 Multiple Resource Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
6.2.2 Multiple Resource Use with Logging . . . . . . . . . . . . . . . . . . . . . . 308
6.2.3 Erroneous Busy Waiting without Resource Hierarchy . . . . . . . . . . . . . 309
6.2.4 Erroneous Busy Waiting with Resource Hierarchy . . . . . . . . . . . . . . . 310
6.2.5 Still Erroneous Busy Waiting with Resource Hierarchy . . . . . . . . . . . . 313
6.2.6 Correct Busy Waiting with Resource Hierarchy . . . . . . . . . . . . . . . . 315
6.2.7 Good low CPU load Busy Waiting with Resource Hierarchy . . . . . . . . . 317
6.2.8 std::mutex with Resource Hierarchy . . . . . . . . . . . . . . . . . . . . . . 318
6.2.9 std::lock_guard with Resource Hierarchy . . . . . . . . . . . . . . . . . . . 319
6.2.10 std::lock_guard and Synchronized Output with Resource Hierarchy . . . . 320
6.2.11 std::lock_guard and Synchronized Output with Resource Hierarchy and acount . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
6.2.12 A std::unique_lock using deferred locking . . . . . . . . . . . . . . . . . . 323
6.2.13 A std::scoped_lock with Resource Hierarchy . . . . . . . . . . . . . . . . . 325
6.2.14 The Original Dining Philosophers Problem using Semaphores . . . . . . . . 326
6.2.15 A C++20 Compatible Semaphore . . . . . . . . . . . . . . . . . . . . . . . . 328
6.3 Thread-Safe Initialization of a Singleton . . . . . . . . . . . . . . . . . . . . . . . . . 330
6.3.1 Double-Checked Locking Pattern . . . . . . . . . . . . . . . . . . . . . . . . 330
6.3.2 Performance Measurement . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
6.3.3 Thread-Safe Meyers Singleton . . . . . . . . . . . . . . . . . . . . . . . . . 334
6.3.4 std::lock_guard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
6.3.5 std::call_once with std::once_flag . . . . . . . . . . . . . . . . . . . . . . 338
6.3.6 Atomics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
6.3.7 Performance Numbers of the various Thread-Safe Singleton Implementations 343
6.4 Ongoing Optimization with CppMem . . . . . . . . . . . . . . . . . . . . . . . . . . 345
6.4.1 CppMem: Non-Atomic Variables . . . . . . . . . . . . . . . . . . . . . . . . 347
6.4.2 CppMem: Locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
6.4.3 CppMem: Atomics with Sequential Consistency . . . . . . . . . . . . . . . . 353
6.4.4 CppMem: Atomics with Acquire-Release Semantics . . . . . . . . . . . . . . 360
6.4.5 CppMem: Atomics with Non-atomics . . . . . . . . . . . . . . . . . . . . . 364
6.4.6 CppMem: Atomics with Relaxed Semantic . . . . . . . . . . . . . . . . . . . 366
6.4.7 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
6.5 Fast Synchronization of Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
6.5.1 Condition Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
6.5.2 std::atomic_flag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
6.5.3 std::atomic<bool> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
6.5.4 Semaphores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
6.5.5 All Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
6.6 Variations of Futures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
6.6.1 A Lazy Future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
6.6.2 Execution on Another Thread . . . . . . . . . . . . . . . . . . . . . . . . . . 387
6.7 Modification and Generalization of a Generator . . . . . . . . . . . . . . . . . . . . . 391
6.7.1 Modifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394
6.7.2 Generalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
6.8 Various Job Workflows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
6.8.1 The Transparent Awaiter Workflow . . . . . . . . . . . . . . . . . . . . . . 401
6.8.2 Automatically Resuming the Awaiter . . . . . . . . . . . . . . . . . . . . . . 403
6.8.3 Automatically Resuming the Awaiter on a Separate Thread . . . . . . . . . . 407
6.9 Thread-Safe Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
7. The Future of C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
7.1 Executors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
7.1.1 A long Way . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
7.1.2 What is an Executor? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
7.1.3 First Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
7.1.4 Goals of an Executor Concept . . . . . . . . . . . . . . . . . . . . . . . . . . 427
7.1.5 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
7.1.6 Execution Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
7.1.7 A Prototype Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . 430
7.2 Extended Futures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
7.2.1 Concurrency TS v1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
7.2.2 Unified Futures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
7.3 Transactional Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
7.3.1 ACI(D) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
7.3.2 Synchronized and Atomic Blocks . . . . . . . . . . . . . . . . . . . . . . . . 444
7.3.3 transaction_safe versus transaction_unsafe Code . . . . . . . . . . . . . . 448
7.4 Task Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
7.4.1 Fork and Join . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
7.4.2 define_task_block versus define_task_block_restore_thread . . . . . . . . 450
7.4.3 The Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
7.4.4 The Scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452
7.5 Data-Parallel Vector Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
7.5.1 Data-Parallel Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
7.5.2 The Interface of the Data-Parallel Vectors . . . . . . . . . . . . . . . . . . . 454
Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
8. Patterns and Best Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460
8.1 History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460
8.2 Invaluable Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
8.3 Pattern versus Best Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
8.4 Anti-Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
9. Synchronization Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464
9.1 Dealing with Sharing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465
9.1.1 Copied Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465
9.1.2 Thread-Specific Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471
9.1.3 Future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
9.2 Dealing with Mutation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
9.2.1 Scoped Locking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
9.2.2 Strategized Locking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
9.2.3 Thread-Safe Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487
9.2.4 Guarded Suspension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494
10. Concurrent Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501
10.1 Active Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
10.1.1 Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
10.1.2 Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
10.1.3 Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
10.1.4 Dynamic Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
10.1.5 Advantages and Disadvantages . . . . . . . . . . . . . . . . . . . . . . . . . 506
10.1.6 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506
10.2 Monitor Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512
10.2.1 Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512
10.2.2 Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512
10.2.3 Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512
10.2.4 Dynamic Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513
10.2.5 Advantages and Disadvantages . . . . . . . . . . . . . . . . . . . . . . . . . 514
10.2.6 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514
10.3 Half-Sync/Half-Async . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519
10.3.1 Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519
10.3.2 Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519
10.3.3 Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520
10.3.4 Dynamic Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521
10.3.5 Advantages and Disadvantages . . . . . . . . . . . . . . . . . . . . . . . . . 521
10.3.6 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
10.4 Reactor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
10.4.1 Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
10.4.2 Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
10.4.3 Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523
10.4.4 Dynamic Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524
10.4.5 Advantages and Disadvantages . . . . . . . . . . . . . . . . . . . . . . . . . 525
10.4.6 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 525
10.5 Proactor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530
10.5.1 Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531
10.5.2 Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531
10.5.3 Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531
10.5.4 Advantages and Disadvantages . . . . . . . . . . . . . . . . . . . . . . . . . 533
10.5.5 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533
10.6 Further Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537
11. Best Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539
11.1 General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539
11.1.1 Code Reviews . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539
11.1.2 Minimize Sharing of Mutable Data . . . . . . . . . . . . . . . . . . . . . . . 541
11.1.3 Minimize Waiting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544
11.1.4 Prefer Immutable Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
11.1.5 Use pure functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547
11.1.6 Look for the Right Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . 548
11.1.7 Use Static Code Analysis Tools . . . . . . . . . . . . . . . . . . . . . . . . . 549
11.1.8 Use Dynamic Enforcement Tools . . . . . . . . . . . . . . . . . . . . . . . . 549
11.2 Multithreading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 550
11.2.1 Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 550
11.2.2 Data Sharing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555
11.2.3 Condition Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
11.2.4 Promises and Futures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
11.3 Memory Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
11.3.1 Don’t use volatile for synchronization . . . . . . . . . . . . . . . . . . . . . 567
11.3.2 Don’t program Lock Free . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
11.3.3 If you program Lock-Free, use well-established patterns . . . . . . . . . . . 567
11.3.4 Don’t build your abstraction, use guarantees of the language . . . . . . . . . 568
11.3.5 Don’t reinvent the wheel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568
Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
12. General Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
12.1 Concurrent Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
12.2 Locking Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572
12.3 Granularity of the Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574
12.4 Typical Usage Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 576
12.4.1 Linux (GCC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 582
12.4.2 Windows (cl.exe) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583
12.5 Avoidance of Loopholes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583
12.6 Contention . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586
12.6.1 Single-Threaded Summation without Synchronization . . . . . . . . . . . . 586
12.6.2 Single-Threaded Summation with Synchronization (lock) . . . . . . . . . . . 588
12.6.3 Single-Threaded Summation with Synchronization (atomic) . . . . . . . . . 589
12.6.4 The Comparison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590
12.7 Scalability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590
12.8 Invariants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
12.9 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595
13. Lock-Based Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596
13.1 Concurrent Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596
13.1.1 A Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597
13.2 Concurrent Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603
13.2.1 A Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603
13.2.2 Coarse-Grained Locking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604
13.2.3 Fine-Grained Locking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
14. Lock-Free Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 619
14.1 General Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
14.1.1 The Next Evolutionary Step . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
14.1.2 Sequential Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
14.2 Concurrent Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 621
14.2.1 A Simplified Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . 622
14.2.2 A Complete Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . 624
14.3 Concurrent Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647
Further Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 648
15. Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649
15.1 ABA Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649
15.2 Blocking Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
15.3 Breaking of Program Invariants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654
15.4 Data Races . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656
15.5 Deadlocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658
15.6 False Sharing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 659
15.7 Lifetime Issues of Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664
15.8 Moving Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 665
15.9 Race Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666
16. The Time Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 668
16.1 The Interplay of Time Point, Time Duration, and Clock . . . . . . . . . . . . . . . . . 669
16.2 Time Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 670
16.2.1 From Time Point to Calendar Time . . . . . . . . . . . . . . . . . . . . . . . 670
16.2.2 Cross the valid Time Range . . . . . . . . . . . . . . . . . . . . . . . . . . . 672
16.3 Time Duration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674
16.3.1 Calculations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
16.4 Clocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679
16.4.1 Accuracy and Steadiness . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679
16.4.2 Epoch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 682
16.5 Sleep and Wait . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 685
17. CppMem - An Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
17.1 The simplified Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
17.1.1 1. Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692
17.1.2 2. Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692
17.1.3 3. Display Relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693
17.1.4 4. Display Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693
17.1.5 5. Model Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693
17.1.6 The Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693
18. Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698
18.1 adress_free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698
18.2 ACID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698
18.3 CAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698
18.4 Callable Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698
18.5 Complexity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699
18.6 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699
18.7 Concurrency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699
18.8 Critical Section . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699
18.9 Deadlock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
18.10 Eager Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
18.11 Executor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
18.12 Function Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
18.13 Lambda Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
18.14 Lazy evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
18.15 Lock-free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701
18.16 Lock-based . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702
18.17 Lost Wakeup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702
18.18 Math Laws . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702
18.19 Memory Location . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702
18.20 Memory Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703
18.21 Modification Order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703
18.22 Monad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703
18.23 Non-blocking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704
18.24 obstruction-free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704
18.25 Parallelism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704
18.26 Predicate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705
18.27 Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705
18.28 RAII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705
18.29 Release Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705
18.30 Sequential Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705
18.31 Sequence Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706
18.32 Spurious Wakeup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706
18.33 Thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706
18.34 Total order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706
18.35 TriviallyCopyable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707
18.36 Undefined Behavior . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707
18.37 volatile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707
18.38 wait-free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 709

C++11 is the first C++ standard that deals with concurrency. The story goes on with C++17, C++20, and will continue with C++23. I'll give you a detailed insight into the current and the upcoming concurrency in C++. This insight includes the theory and a lot of practice.

  • C++11 and C++14 have the basic building blocks for creating concurrent or parallel programs.

  • With C++17, we got the parallel algorithms of the Standard Template Library (STL). That means most of the algorithms of the STL can be executed sequentially, in parallel, or vectorized.

  • The concurrency story in C++ goes on. With C++20, we got coroutines, atomic smart pointers, semaphores, latches, and barriers.

  • C++23 supports the first concrete coroutine: std::generator.

  • With future C++ standards, we can hope for executors, extended futures, transactional memory, and more.


Похожее:

Список отзывов:

Нет отзывов к книге.