// lesson: barriers-rendezvous
Barriers and Rendezvous
sync.WaitGroup is a one-shot: N workers finish, one waiter proceeds. A
cyclic barrier is the reusable, symmetric version โ N goroutines each
call Await, everyone blocks until the Nth arrives, then all of them are
released together and the barrier resets for the next round. Think lockstep
simulation phases, parallel iterative solvers, or "everyone reloads config
between batches".
The bug that kills naive implementations is generation mixing. A fast
goroutine released from round k loops around and calls Await for round
k+1 while a slow sibling from round k hasn't woken up yet. If your state
is just a counter, the fast arrival corrupts the round the sleeper is still
in. The standard fix is a generation number: waiters sleep while
gen == myGen, and the last arrival increments gen, resets the count, and
broadcasts.
sync.Cond fits perfectly here โ one mutex, Wait in a predicate loop,
Broadcast from the last arrival. You can also do it with a channel per
generation. Either way: nobody gets out early, and nobody's arrival leaks
into the next round.
โบ Cyclic Barrier
30 ptsImplement:
func NewBarrier(n int) *Barrier
func (b *Barrier) Await()
Required semantics (n >= 1; every goroutine uses the barrier for its whole lifetime):
Awaitblocks untilngoroutines (counting the caller) have called it in the current generation, then allnreturn and the barrier resets.- No early release: with only
n-1arrivals, nobody returns. - Reusable: the same
Barriermust work for many consecutive generations, including when fast goroutines re-enterAwaitfor the next generation while slow ones are still waking from the last. The tests run 4 goroutines through 25 generations and check an arrival counter per generation at every release.
Log in to submit a solution and earn points.