liveBook · Manning

Sync.Cond

As explained in 100 Go Mistakes and How to Avoid Them

sync.Cond is a Go synchronization type that coordinates goroutines waiting for a condition associated with a locker.

A common mistake is replacing a condition notification with a shared channel. A channel message reaches only one receiving goroutine, so multiple listeners can observe different balance updates. In a donation-goal example, the $10 listener may receive $11 instead of the $10 notification while the $15 listener still succeeds. section 9.12

A mutex-only fix avoids unsafe shared access but creates a busy loop: each listener repeatedly checks the balance, wasting CPU while waiting. sync.Cond provides condition-associated waiting and lets the updater notify all waiting listeners when the balance changes. section 9.12 section 9.15

Notify every donation-goal listener

Store a sync.Cond with a mutex and a shared balance. Each listener locks the condition, waits while its goal is unmet, then prints the reached balance. The updater increments the balance while holding the same lock and calls Broadcast afterward, allowing both the $10 and $15 listeners to receive notifications. section 9.12

type Donation struct {
    cond    *sync.Cond                    #1
    balance int
}
 
donation := &Donation{
    cond: sync.NewCond(&sync.Mutex{}),    #2
}
 
// Listener goroutines
f := func(goal int) {
    donation.cond.L.Lock()
    for donation.balance < goal {
        donation.cond.Wait()              #3
    }
    fmt.Printf("%d$ goal reached\n", donation.balance)
    donation.cond.L.Unlock()
}
go f(10)
go f(15)
 
// Updater goroutine
for {
    time.Sleep(time.Second)
    donation.cond.L.Lock()
    donation.balance++                    #4
    donation.cond.L.Unlock()
    donation.cond.Broadcast()             #5
}

The complete listing contrasts condition waiting with busy polling and shared-channel delivery: listeners test their own goals in a loop, while the updater broadcasts after each balance increment. section 9.12

Choose the coordination primitive according to the notification requirement:

  • Use a shared channel when each update should be consumed by one receiving goroutine. section 9.12
  • Use sync.Cond when one state change should notify multiple goroutines waiting for different conditions. section 9.12 section 9.15

How 100 Go Mistakes and How to Avoid Them covers it

How deep it goes
Explains busy-loop and channel alternatives before showing a complete sync.Cond implementation with locking, waiting, and broadcasting.
Examples
Uses donation balances, $10 and $15 goals, busy polling, shared-channel delivery, and Broadcast-based waiting.
What it assumes
Assumes familiarity with goroutines, mutex-protected shared state, channels, and basic synchronization choices.
What you can do after
Apply it via sync.Cond to notify multiple goroutines whenever shared state changes.
How it connects
Connects sync.Cond to goroutines, mutexes, channels, shared state, and synchronization primitives.

Also explained in

Compare how 2 books explain sync.Cond →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Go Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.