A common mistake is using a channel when every listener must react to the same update. Each channel message reaches only one goroutine; sync.Cond.Broadcast wakes all goroutines currently waiting on its condition. section 9.12
Broadcasting donation updates
Protect the shared balance with the condition’s locker. Each listener locks, checks its goal in a for loop, and calls Wait while the goal remains unmet. The updater increments the balance under the same lock, unlocks, then calls Broadcast. Waiting listeners wake, reacquire the lock, recheck the condition, and print when their individual goals are reached. 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
}
Use the complete Go listing to trace the locker, repeated condition check, Wait call, balance update, and Broadcast call. section 9.12
