Latches in C++20
modernescpp.com
modernescpp.com
CountDownLatch workDone = new CountDownLatch(6);
workDone.countDown(); // mark an event
workDone.await(); // wait until the counter reaches zero
Even if latches also refer to another concept, it's still positive to see some naming consistency across languages. What name would you have preferred?[1] https://docs.oracle.com/en/java/javase/11/docs/api/java.base...
A latch is a circuit that takes on a value (high or low, 1 or 0) when some some gating signal arrives (like a clock pulse) and then holds that value after the input is removed.
It is named after a door latch; a door latches when you close it and then holds that state: you can't pull it open again without using the handle/knob.
If something is called "latch" which does not change its state once in order to reflect an input event, and then hold that state until explicitly recent, then it's misnamed due to abusing the metaphor.
The barrier metaphor is the right one for an object that is hit some predetermined number of times and then fires an event (like releasing some waiting thread(s)). That predetermined number of events is its "barrier potential": the threshold that must be met to break through the barrier.
Memory barriers and POSIX-style barriers are semantically related; both mechanisms ensure that certain events are not re-ordered between adjacent phases; they stay on their side of the barrier.
(That conflicts with "fence register"; a concept in non-virtualized memory management whereby each running process is confined to accessing range of memory delimited by values held in fence registers.)
The reusable variant is called a std::barrier.
In a barrier signaling and waiting is a single atomic operation. Each thread (of a group of N) reaching a barrier will wait until all N threads have reached an waited (and implicitly signaled) it.
A countdown latch is an event that will release one (or more) waiter only after has been signaled N times. Signaling and waiting threads are not necessarily the same and often are distinct sets.
I guess you could build a barrier from a countdown latch, but I suspect that a trivial mapping of barrier::wait to latch::signal+wait is going to racey and you need an additional sinchronization primitive. For example pthread_barrier_wait requires an additional mutex (similar to condition variables).
edit: std::barrier has (optionally) separate singal+wait and uses an explicit arrival token instead of a mutex to tie the signaling with waiting.
In practice a barrier and a countdown latch are used for different purposes (the former to coordinate multiple symmetric threads across phases of a distributed computation, the latter to wait for completion of N events).
Yeah that's exactly what std::latch::arrive_and_wait does.
I don't think atomicity is a thing here though... arrive_and_wait() is just count_down() followed by wait().
> A countdown latch is an event that will release one (or more) waiter only after has been signaled N times. Signaling and waiting threads are not necessarily the same and often are distinct sets.
C# still calls this a Barrier, except that it requires one of the waiters to be a participant (see AddParticipant() and SignalAndWait()): https://docs.microsoft.com/en-us/dotnet/api/system.threading...
They even allow removing participants!
This is a little bit like a mutex that has a try_lock. It's not strictly the vanilla Computer Science "mutex" with lock/unlock per se, but it's not a fundamentally different concept; it's just a handy yet pretty close generalization. I guess if you really want to give this a new name then maybe it's not a terrible idea given it's a slight generalization of a barrier, but latch is certainly not going to be any more accurate (or less confusing) than barrier.
"There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors."
[0] https://docs.oracle.com/en/java/javase/15/docs/api/java.base...
Just because Java calls it something that doesn't mean it is "typically" called that thing.
I personally "prefer to look at" integers as not having state.
> Just because Java calls it something that doesn't mean it is "typically" called that thing.
It's only been there since 2004 and is named the same in C#
No. There are lots of "open" states with different counter values. That you choose to call them all "open" and not observe the differences doesn't change this. It sounds like you've never studied state machines, so I recommend reading up on them; here's a starting point: https://en.wikipedia.org/wiki/State_(computer_science)#Finit...
> It's only been there since 2004 and is named the same in C#
No it's not... where did you get this? C# has CountdownEvent and Barrier. It's not called "latch".
And, for that matter, OpenMP also has #pragma omp barrier since 1998... https://www.openmp.org/wp-content/uploads/cspec10.pdf#page=2...
There's no point continuing this argument so let's just leave it here.
Yeah cause you're insufferable.
Most importantly, latch is level-triggered, just like the synchronization primitive.
A simple mutex latches open when you unlock it, and then latches locked when something locks it again.
Something that triggers, flips state and cannot be reset might be called a "fuse".
That could work here in another way: since there is a count-down, that's like a dynamite fuse burning.
It doesn't to me... I'm not following unfortunately.
Barriers are level-triggered too. Like, physical ones. Push with enough force against a barrier and it'll break down.
This contrasts to std::barrier which auto-resets once signaled[1].
As such I think it would be better if they had called it std::latched_barrier or similar.
Too bad they couldn't qualify it somewhere further down below std::. Something like std::thread::barrier or similar might be easier to understand.
Computer engineers are HW designers, may not go into that field but it's pretty engrained in their courses.
source: am computer engineer.
Edit: Ok so a (Windows) event is one bit, a C++ latch is a one-shot counter, and a C++ barrier is a cyclic counter. But I thought a barrier in general computer science terms is just a one-shot counter, which is what they're calling a latch in C++?
class ThreadLatch
{
public:
ThreadLatch(std::size_t count = 0)
: _count(count) {}
void inc()
{
std::lock_guard<std::mutex> lock(_mutex);
++_count;
}
void dec()
{
std::lock_guard<std::mutex> lock(_mutex);
assert(0 != _count);
--_count;
if(0 == _count)
{
_condition.notify_all();
}
}
void wait()
{
std::unique_lock<std::mutex> lock(_mutex);
while(_count > 0)
{
_condition.wait(lock);
}
}
private:
std::mutex _mutex;
std::condition_variable _condition;
std::size_t _count;
};A latch allows one or more threads to wait until a set of operations being performed in other threads completes [0].
[0] https://docs.oracle.com/javase/8/docs/api/java/util/concurre...
A barrier (what this thing is) blocks threads until the counter reaches zero.
I would never attempt to implement a full condvar.
ws.Add(1)
[...]
wg.Done()
in Go?[0]: https://docs.oracle.com/javase/7/docs/api/java/util/concurre...
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/co...
Before this stuff landed, Java's concurrency model was a lot less nice to deal with. Good high level abstractions are important. Nice to see the same kind of primitives are being added to C++.
Several other C++ libraries also provided condition variables, which latches are a variant of, along with barriers and flex_latches.
But the semantics are not sufficiently different as to allow for any notably new use cases/code flow, certainly not from the examples I've seen. Every one of them could have been written using condition variables at any point in the last 30 years and would look almost indistinguishable.
"I enjoyed programming in Java, and being relieved of the responsibility for producing a quality product."
Yeah java 6/7 was verbose, but it's nothing representative of the language now. You might as well point out the problems of C++03. Streams, lambdas, method references, records, and local variable inference make it pretty fluent to write and at the very least it has a sane standard library (I can't say as much for Scala).
Also as for their intro problem what type of Java programmer worth their salt can't do:
while (true)
System.out.print(System.in.read());