Go

Implement a reusable barrier (CyclicBarrier) that N goroutines wait on before moving to the next phase.

Question 522HardGo 1.22 to 1.25

The hard part is making the barrier reusable. A fast goroutine can finish phase k and call Wait for phase k+1 before a slow waiter from phase k has even woken up. If waiters check count, the fast goroutine's increment corrupts it and the slow goroutine sleeps forever. The fix is a generation counter: each waiter remembers the generation it arrived in and waits until that generation changes.

type Barrier struct {
	mu    sync.Mutex
	cond  *sync.Cond
	n     int
	count int
	gen   uint64
}

func NewBarrier(n int) *Barrier {
	b := &Barrier{n: n}
	b.cond = sync.NewCond(&b.mu)
	return b
}

// Wait blocks until n goroutines have called Wait for the current phase.
// It reports true for exactly one goroutine per phase (the last arriver),
// which is handy for running a per-phase action.
func (b *Barrier) Wait() bool {
	b.mu.Lock()
	defer b.mu.Unlock()
	gen := b.gen
	b.count++
	if b.count == b.n {
		b.count = 0
		b.gen++ // open the barrier and start the next generation
		b.cond.Broadcast()
		return true
	}
	for gen == b.gen {
		b.cond.Wait()
	}
	return false
}

Channel alternative: keep a release chan struct{} for each generation. The last arriver calls close(release) and swaps in a fresh channel while holding the mutex. The other goroutines grab the current channel under the lock and then wait with select { case <-ch: case <-ctx.Done(): }. That makes waits cancellable, but a cancelled waiter leaves count wrong. Java handles this by marking the barrier broken and failing every waiter, and you have to do something similar.

Why not sync.WaitGroup? A WaitGroup is one-way: the workers call Done and a different goroutine calls Wait. Reusing it needs another Add before anyone calls Wait again. Calling Add while a Wait is still in progress is a documented misuse, and it races across phases. What the interviewer is looking for: spotting the phase-overlap race and fixing it with a generation number, plus a plan for cancellation (a broken-barrier state).

More on Classic Concurrency Coding Problems

All 16 Classic Concurrency Coding Problems questions