C++11 and later standards introduced a new threading library. This library includes utilities for starting and managing threads. It also provides synchronization primitives such as mutexes and other locks, as well as atomic variables and related utilities.
Having a standard way to manage concurrency in C++ is a major improvement. Before these features were introduced, C++ projects relied on a variety of libraries and approaches to handle concurrency.
In this post, we will look at the benefits of reading the book "Concurrency with Modern C++" written by Rainer Grimm.
Pragmatic approach
In computer science, some books are primarily academic and aimed at students, while others are written for developers who need practical guidance on solving real-world problems when building a product. This book follows a pragmatic approach, and from the beginning it references the examples package and explains how to compile them. The goal is to practice each solution provided in the book.
The whole picture from the beginning
In general, we can get a sense of a book's content by looking at the table of contents and reading the introduction. However, in many cases that’s not really enough to have a clear idea of the book’s goals.
What’s interesting about this book is that it has an 8-page “Quick Overview” section that clearly explains the problem, the solutions, and the features the new standards provide.
Memory model clearly explained
Starting with the Quick Overview, the constraints of the memory model are clearly explained.
The foundation of multithreading is a well-defined memory model. This memory model has to deal with the following aspects: • Atomic operations: operations that can be performed without interruption. • Partial ordering of operations: sequence of operations that must not be reordered. • Visible effects of operations: guarantees when operations on shared variables are visible in other threads.
And in the section dedicated to the memory model, the author provides an in-depth analysis of memory constraints, along with numerous code samples that make it easier to understand memory handling in concurrent scenarios. Even more useful are the illustrations used to explain the problems and their solutions.
This section also introduces the features provided by the newer standards for handling memory in concurrent programs.
Multithreading demystified
Too many programmers writing multithreaded programs learn to create a bunch of threads and get them mostly working, but then the threads go completely out of control and the programmer doesn’t know what to do. After that, fixing a bug or adding code becomes a headache. Sometimes fixing one bug can introduce many others.
It is therefore advisable to master the basics of multithreading before using it in production code. Fortunately, C++ has had a multithreading interface since C++11, and this interface has all the basic building blocks for creating multithreaded programs. It’s better to have a standard way to deal with threads.
One strength of the book's Multithreading section is its step-by-step approach, which makes it useful even for beginners who are not yet familiar with threads. I would also recommend this section to experienced C++ developers. Personally, even after working with threads for many years, I discovered several interesting details and new features.
As in the memory model section, numerous code samples and illustrations make the multithreading concepts easier to understand.
Case studies to practice the theory
After presenting the theory on the memory model and the multithreading interface, the author applies it in practice and provides you with a few performance numbers.
The case studies are easy to follow, such as the one on calculating the sum of a vector. The author also explains in depth the different implementation options available with modern C++ features.
After reading and practicing the first case study, you will have a practical understanding of many concurrency issues and how to address them. I recommend this case study to any developer who wants to master C++ concurrency.
Challenges and best practices at the end
After covering the memory model and multithreading, and reinforcing them through case studies, the author provides several interesting challenges. Here is his motivation for including them:
Programming concurrently is inherently complicated. This holds in particular true if you use C++11 and C++14 features. I have not even talked about the memory model yet. My hope is that if I dedicate a whole chapter to the challenges of concurrent programming, you may become more aware of the pitfalls.
The author also provides several best practices for dealing with concurrency, as he explains:
This chapter provides you with a simple set of rules for writing well-defined and fast, concurrent programs in modern C++. Multithreading, and in particular parallelism and concurrency, is quite a new topic in C++; therefore, more and more best practices will be discovered in the coming years. Consider the rules in this chapter not as a complete list; but rather as a necessary starting point that will evolve over time.
Conclusion
While reading the book, it becomes clear that the author is a programmer with extensive experience solving real problems in C++ projects, which explains the book's pragmatic approach. We recommend this book to any developer who wants to master concurrency in modern C++.
