What happens sending on an unbuffered channel before any receive?
State exactly what this program does at runtime (prints something, blocks silently, or aborts) and explain why. Then give a one-line fix that makes it print 1.
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
Predict the outcome.
It deadlocks: fatal error: all goroutines are asleep - deadlock!. An unbuffered send blocks until a receiver is ready, but the only goroutine is blocked on the send, so the receive never runs. Fix: send from a separate goroutine, or use make(chan int, 1).
- ✗Thinking an unbuffered channel buffers one value — its capacity is zero
- ✗Expecting the runtime to hang silently rather than report
deadlock! - ✗Believing one goroutine can both send and then receive on an unbuffered channel in sequence
- →Why can the Go runtime detect this deadlock but not one involving a blocked syscall?
- →How does moving the send into
go func(){ ch <- 1 }()fix it?
What happens?
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
Result
fatal error: all goroutines are asleep - deadlock!
Why
make(chan int) creates an unbuffered channel (capacity 0). The send ch <- 1 is synchronous: it blocks until some other goroutine is ready to receive.
Here only one goroutine runs — main. It blocks on ch <- 1 and never reaches the <-ch line. There is no receiver, so no progress. The runtime sees that all goroutines are asleep and aborts the program with deadlock!.
Two fixes:
// 1) send from a separate goroutine
go func() { ch <- 1 }()
fmt.Println(<-ch) // 1
// 2) a buffered channel holds the value without a receiver
ch := make(chan int, 1)
ch <- 1
fmt.Println(<-ch) // 1