Why does this program deadlock when a goroutine ranges over a channel that is never closed?
A consumer goroutine ranges over ch while main sends two values and waits on the WaitGroup. The program deadlocks instead of finishing.
func main() {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for v := range ch {
fmt.Println(v)
}
}()
ch <- 1
ch <- 2
wg.Wait()
}
Identify the bug and explain the cause.
for v := range ch keeps receiving until the channel is closed. The producer sends 1 and 2 but never calls close(ch), so the consumer blocks forever after draining them, wg.Done() never runs, and wg.Wait() blocks too — deadlock. Fix: close(ch) after the last send.
- ✗Thinking
range chstops when the channel is empty rather than when it is closed - ✗Closing the channel from the receiver instead of the sender
- ✗Forgetting an unclosed channel keeps the ranging goroutine alive, so
wg.Wait()never returns
- →Who is responsible for closing a channel, and why never the receiver?
- →How would a
selectwith adonechannel let the consumer exit without a close?
Find the bug
func main() {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for v := range ch { // blocks forever waiting for close
fmt.Println(v)
}
}()
ch <- 1
ch <- 2
wg.Wait()
}
Why it deadlocks
for v := range ch is a receive loop that ends only when the channel is closed. While the channel is open, once all values are drained range blocks waiting for the next one.
The producer sends 1 and 2, the consumer prints them — and then range hangs waiting for more values or a close. Because close(ch) is never called:
- the consumer goroutine sits in
rangeforever; defer wg.Done()never runs;wg.Wait()inmainwaits on a counter that never reaches zero.
All goroutines are asleep → deadlock!.
✅ The fix is to close the channel after the last send (the sender closes):
ch <- 1
ch <- 2
close(ch) // range ends, wg.Done runs
wg.Wait()