Additional Synchronization Primitives in C++20
Learn about the new synchronization primitives in C++20 (latches and barriers) and how they're used.
We'll cover the following...
C++20 comes with a few additional synchronization primitives, namely std::latch
, std::barrier
, and std::counting_semaphore
(and the template specialization std::binary_semaphore
). This lesson will be an overview of these new types and some typical scenarios where they can be useful. We’ll begin with std::latch
.
Using latches
A latch is a synchronization primitive that can be used for synchronizing multiple threads. It creates a synchronization point where all threads must arrive at. We can think of a latch as a decrementing counter. Typically, all threads decrement the counter once and then wait for the latch to reach zero before moving on.
A latch is constructed by passing an initial value of the internal counter:
auto lat = std::latch{8}; // Construct a latch initialized with 8
Threads can then decrement the counter using count_down()
:
lat.count_down(); // Decrement but don't wait
A thread can wait on the latch to reach zero:
lat.wait(); // Block until zero
It’s also possible to check (without blocking) to see whether the counter has reached zero:
if (lat.try_wait()) {// All threads have arrived ...}
It’s common to wait for the latch to reach zero right after decrementing the counter, as follows:
lat.count_down();lat.wait();
In fact, this use case is common enough to deserve a tailor-made member function; arrive_and_wait()
decrements the latch and then waits for the latch to reach zero:
lat.arrive_and_wait(); // Decrement and block while not zero
Joining a set of forked tasks is a common scenario when working with concurrency. If the tasks only need to be joined at the end, we can use an array of future objects (to wait on) or just wait for all the threads to complete. But in other cases, we want a set of asynchronous tasks to arrive at a common synchronization point, and then have the tasks continue running. These situations typically occur when some initialization ...