Why is chan struct{} preferred for signaling, and how does close act as a broadcast?
Question 206MediumGo 1.22 to 1.25
struct{} has size 0, so the channel buffer uses no memory for elements, and the type tells the reader that the value means nothing and the event is the point. A send wakes exactly one receiver. A close wakes all current and future receivers, because a receive on a closed channel never blocks. That makes close a one-shot broadcast.
start := make(chan struct{})
var wg sync.WaitGroup
for i := range 10 {
wg.Add(1)
go func() {
defer wg.Done()
<-start // all 10 park here
run(i)
}()
}
close(start) // releases all 10 at once (a "starting gun")
wg.Wait()
This is the basis of context.Done(), errgroup, and shutdown signals. The limitation is that closing is one-shot, since a channel can't be reopened. For repeated broadcasts, swap in a new channel under a mutex (the "generation channel" pattern) or use sync.Cond.Broadcast.
More on Channels & select
- Q204Implement a worker pool with result collection and proper shutdown.
- Q205What is a goroutine leak caused by channels? Show one and fix it.
- Q207What does this print? (len and cap of channels)
- Q208Channels or mutexes: how do you decide?
- Q209Explain the pipeline pattern and how to cancel it properly.
- Q210What happens if you send on a closed channel inside a
selectwith adefault?