Latches and barriers are coordination types that enable some threads to wait until a counter becomes zero. You can use a
std::latch only once, but you can use a
std::barrier more than once. Today, I have a closer look at latches.
Concurrent invocations of the member functions of a
std::latch or a
std::barrier are no data race. A data race is such a crucial term in concurrency that I want to write more words to it.
A data race is a situation, in which at least two threads access a shared variable at the same time and at least one thread tries to modify the variable. If your program has a data race, it has undefined behavior. This means all outcomes are possible and therefore, reasoning about the program makes no sense anymore.
Let me show you a program with a data race.
100 threads adding 50 euros to the same account (1) using the function
addMoney (2). The initial account is 100 (3). The crucial observation is that the writing to the account is done without synchronization. Therefore we have a data race and, consequently, undefined behavior. The final balance is between 5000 and 5100 euro (4).
What is happening? Why are a few additions missing? The update process
to.balance += amount; in line (1) is a so-called read-modify-write operation. As such, first, the old value of
to.balance is read, then it is updated, and finally is written. What may happen under the hood is the following. I use numbers to make my argumentation more obvious
- Thread A reads the value 500 euro and then Thread B kicks in.
- Thread B read also the value 500 euro, adds 50 euro to it, and updates
to.balanceto 550 euro.
- Now Thread A finished its execution by adding 50 euro to
to.balanceand also writes 550 euro.
- Essential the value 550 euro is written twice and instead of two additions of 50 euro, we only observe one.
- This means, that one modification is lost and we get the wrong final sum.
First, there are two questions to answer before I present
std::barrier in detail.
- What is the difference between these two mechanisms to coordinate threads? You can use a
std::latchonly once, but you can use a
std::barriermore than once. A
std::latchis useful for managing one task by multiple threads; a
std::barrieris helpful for managing repeated tasks by multiple threads. Additionally, a
std::barrierenables you to execute a function in the so-called completion step. The completion step is the state when the counter becomes zero.
- What use cases do latches and barriers support that cannot be done in C++11 with futures, threads, or condition variables combined with locks? Latches and barriers address no new use cases, but they are a lot easier to use. They are also more performant because they often use a lock-free mechanism internally.
Let me continue my post with the simpler data type of both.
Now, let us have a closer look at the interface of a
The default value for
upd is greater than the counter or negative, the behaviour is undefined. The call
lat.try_wait() does never wait as its name suggests.
The following program
bossWorkers.cpp uses two
std::latch to build a boss-workers workflow. I synchronized the output to
std::cout use the function
synchronizedOut (1). This synchronization makes it easier to follow the workflow.
The idea of the workflow is straightforward. The six workers
david in the
main-program have to fulfill their job. When they finished their job, they count down the
std::latch workDone (2). The boss (
main-thread) is blocked in line (3) until the counter becomes 0. When the counter is 0, the boss uses the second
std::latch goHome to signal its workers to go home. In this case, the initial counter is
1 (4). The call g
oHome.wait (5) blocks until the counter becomes 0.
When you think about this workflow, you may notice that it can be performed without a boss. Here is the modern variant:
There is not much to add to this simplified workflow. The call
workDone.arrive_and_wait(1) (1) is equivalent to the calls
count_down(upd); wait();. This means the workers coordinate themself and the boss is no longer necessary such as in the previous program
std::barrier is quite similar to a
std::barrier‘s strength is it to perform a job more than once. In my next post, I will have a closer look at barriers.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, and Bhavith C Achar.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
|My special thanks to Embarcadero|
|My special thanks to PVS-Studio|
|My special thanks to Tipi.build|
|My special thanks to Take Up Code|
I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
- Embedded Programmierung mit modernem C++ 12.12.2023 – 14.12.2023 (Präsenzschulung, Termingarantie)
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
- C++ – The Core Language
- C++ – The Standard Library
- C++ – Compact
- C++11 and C++14
- Concurrency with Modern C++
- Design Pattern and Architectural Pattern with C++
- Embedded Programming with Modern C++
- Generic Programming (Templates) with C++
- Clean Code with Modern C++
- Phone: +49 7472 917441
- Mobil:: +49 176 5506 5086
- Mail: schulung@ModernesCpp.de
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++ Mentoring,