...

/

Advanced Concepts in Concurrent Programming

Advanced Concepts in Concurrent Programming

Learn about protecting critical sections, avoiding deadlocks, and using condition variables in advanced concurrent programming.

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:

Press + to interact
auto counter = 0; // Warning! Global mutable variable
auto 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:

Press + to interact
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 ...