Advanced Concepts in Concurrent Programming
Learn about protecting critical sections, avoiding deadlocks, and using condition variables in advanced concurrent programming.
We'll cover the following...
Protecting critical sections
As we already mentioned, our code must not contain any data races. Unfortunately, writing code with data races is very easy. Finding the critical sections and protecting them with locks is something we constantly need to think about when writing concurrent programs in this style using threads.
C++ provides us with a std::mutex
class that can be used for protecting critical sections and avoiding data races. We will demonstrate how to use a mutex with a classic example using a shared mutable counter variable updated by multiple threads.
First, we define a global mutable variable and the function incrementing the counter:
auto counter = 0; // Warning! Global mutable variableauto increment_counter(int n) {for (int i = 0; i < n; i++) {++counter;}}
The main()
function that follows creates two threads that will both execute
the increment_counter()
function. Note also in this example how we can pass arguments to the function invoked by the thread. We can pass an arbitrary number of arguments to the thread constructor to match the parameters in the signature of the function to be called. Finally, we assert that the counter has the value we would expect it to have if the program was free from race conditions:
int main() {constexpr auto n = int{100'000'000};{auto t1 = std::jthread{increment_counter, n};auto t2 = std::jthread{increment_counter, n};}std::cout << counter << '\n';// If we don't have a data race, this assert should hold:assert(counter == (n * 2));}
This program will most likely fail. The assert()
function doesn’t hold since the program currently contains a race condition. When we repeatedly run the program, we end up with different counter values. Instead of reaching the value 200000000
, we once ended up with no more than 137182234
. This example is very similar to the data race example illustrated earlier in this chapter.
The line with the ...