A barrier synchronizes a fixed group of concurrent executions at a shared point. Each participant calls Wait() after reaching that point and remains suspended until every participant has arrived. The barrier then releases the group together, letting the next phase begin. Unlike a waitgroup, which waits for tasks to finish, a barrier coordinates executions before or between pieces of work. section 6.2 section 6.2.1
Barriers fit repeated, phase-based work. Goroutines can compute independently, wait for input to become ready, compute again, then wait while another execution collects results. A reusable barrier is a cyclic barrier: after releasing one group, it can synchronize the same participants at a later execution point. section 6.2.1
A condition-variable barrier needs three pieces of shared state:
- A barrier size: the total number of participating goroutines expected at each Wait() point. section 6.2.2
- A wait counter: incremented as each goroutine arrives, tracking how many are currently waiting. section 6.2.2
- A condition variable and mutex: the mutex protects the counter; the condition variable suspends early arrivals and broadcasts when the group is complete. section 6.2.2
Wait() combines the roles that Done() and Wait() play for a waitgroup into one atomic operation. A goroutine locks the barrier state and increments the counter. If it is not the last participant, it waits on the condition variable. If its arrival brings the count to the barrier size, it resets the counter to zero and broadcasts to unblock the suspended goroutines. Resetting the count makes the barrier reusable for another cycle. section 6.2.1 section 6.2.2
Fast and slow goroutines meeting repeatedly
Two goroutines share a barrier of size two. Red works for four seconds while Blue works for ten. Red reaches Wait() first and pauses; when Blue reaches Wait(), both resume at nearly the same time. On the next cycle, Red again waits for Blue. The output makes the key behavior visible: a barrier does not equalize work duration, but it prevents either participant from passing the synchronization point alone. section 6.2.2
Figure 6.10 Waiting when not all goroutines are at barrier, and broadcasting and resuming barriers when all goroutines are at the barrier
Compare the early-arrival path, which waits, with the final-arrival path, which resets the count and broadcasts to the group. section 6.2.2
All intended participants must reach every barrier cycle. The configured size is therefore part of the protocol: it must match the goroutines that share the barrier, including a coordinating main goroutine when it also waits. A barrier is useful when work must proceed in ordered stages, rather than merely when a caller needs notification that tasks have ended. section 6.2.2 section 6.2.3
Concurrent matrix multiplication in phases
For a 3 × 3 result matrix, three row goroutines and main use a barrier of size four. Main generates the input matrices while row goroutines wait. Its first Wait() releases the row goroutines to calculate their assigned rows. Each row then waits again; after all rows finish, main is released to print the result and load the next matrices. Reusing both the goroutines and barrier supports repeated multiplications. section 6.2.3
An alternative is to create a fresh set of row goroutines for each matrix instead of reusing workers through a barrier. That design still needs a way to notify main when all row calculations are complete. Barriers are consequently most natural when the same group repeatedly crosses the same coordination boundaries. section 6.3


