Recommended with reservations.
First, I’d like to thank Packt for agreeing to provide me with a hard copy of the book as I don’t have an e-reader to read the 424-pages-long pdf on. If you do prefer reading a digital copy, buying the hard copy will get you a free pdf version as well. It’s a shame, though, that most of the cross references and links in the pdf are not clickable, which runs against the usefulness of a digital copy.
Perhaps it’s the standard today but the authors declare usage of “cutting-edge” AI in writing the book, although only to “enhance the language and clarity” of the text. I still wish there was a more tight language editing as there are still a few awkwardly phrased sentences, or maybe it’s just me being a non-native English speaker.
The book is split into 5 parts. The first, ‘Foundations of Parallel Programming and Process Management’, covers the basics of concurrent programming, including the classic parallel vs. concurrency distinction. Much of this part is about processes rather than threads (focusing on Linux), but strangely no mention of processes is found in the later parts of the book, despite the fact that many applications today rely on multi-process architecture to achieve concurrency. The C++17 parallel algorithms (which will get range overloads in C++26) are not even mentioned briefly.
The second part, ‘Advanced Thread Management and Synchronization Techniques’, covers all the details of standard C++ threads, mutexes and atomics and other synchronization primitives. The section about the C++ memory model is decent in my mind because it doesn’t try to be fully comprehensive, which would be impossible in a few pages, but rather focuses on the key concepts needed to understand how atomics work. There are quite a lot of code examples: most of them use sleep to simulate work being done, which is not ideal as junior developers (probably the target audience of this book) tend to use sleeping to bypass race conditions, a problem one of the examples later on (‘Testing callbacks’, page 347) suffers from. This part ends with an example of a lock-free single-producer single-consumer queue using atomics (interestingly avoiding the usual warning to avoid lock-free programming altogether), but I’d like to see how the calling code would look without having to resort to busy-waiting.
Then the book moves to the high level concurrency abstractions like futures, promises and coroutines. There’s a whole chapter about std::async. The authors show how to implement coroutines from scratch if you really have to, otherwise moving to the next part will show you how to use Boost Asio and Cobalt libraries and their coroutine support types instead. I like the fact that the book advocates the usage of libraries like Boost and spdlog as many C++ programmers (especially in the embedded world) are somehow still reluctant to use third party libraries.
The last part, and arguably the most important topic, is about debugging, testing and optimizing concurrent code. It covers logging libraries, debuggers, sanitizers and profiling tools. The examples in this part, unfortunately, are too simplistic to demonstrate real life issues. I mean, you wouldn’t normally log every time a lock is acquired to show there’s a deadlock caused by mutexes being locked in a different order. The section about mocking is particularly bad as in fact it demonstrates testing the mock object and not the actual code. I could spot another race condition in one of the examples (‘Testing multiple threads’, page 353) where the code does not lock the mutex used for waiting on a condition variable when modifying the counter. Despite the counter being atomic, the mutex must be locked, otherwise the waiting thread might miss the notification and wait forever. I want to join the authors in their recommendation of using reverse debugging tools for tracking down race conditions and other hard to find bugs. I use rr (https://rr-project.org/) myself and it’s a life saver.
All the examples are available on GitHub (https://github.com/PacktPublishing/Asynchronous-Programming-with-CPP), with CMake build files. It could have been useful to have a Dockerfile as well to make it easier to get all the dependencies (including a recent compiler) installed. I spent quite some time on that, trying vcpkg first, but failing to understand their complicated versioning scheme. With Conan, it was much easier to get everything working.
Overall, I think the book can be useful as a reference for thread-based concurrency in C++ for developers not familiar with the recent standards or perhaps coming from different programming languages. Learning about the tools covered in the last section will be helpful to any junior programmer.
Website: https://www.packtpub.com/en-gb/product/asynchronous-programming-with-c-9781835884249
Code Site: https://github.com/PacktPublishing/Asynchronous-Programming-with-CPP










