Safely closing a channel requires coordinating its sender and receivers. Closing while another goroutine sends causes a panic; failing to stop goroutines can leak resources. section 5.3.2
Listing 5.8 Improper channel close
package main
import (
"fmt"
"time"
)
func main() {
msg := make(chan string)
until := time.After(5 * time.Second)
go send(msg) #1
for { #2
select {
case m := <-msg: #3
fmt.Println(m)
case <-until: #4
close(msg) #4
time.Sleep(500 * time.Millisecond) #4
return #4
} #4
}
}
func send(ch chan string) { #5
for {
ch <- "hello"
time.Sleep(500 * time.Millisecond)
}
}
The improper-close listing shows main closing a message channel during a timeout while send continues writing, producing a send-on-closed-channel panic. section 5.3.2
Use these practical rules when designing shutdown:
- Let a sender close the channel, with protective coordination around the operation. section 5.3.2
- Add a separate done channel to notify the sending goroutine that it should stop. section 5.3.2
- Have the sender select on done, close the output channel, and return; use directional channel types to clarify roles. section 5.3.2
Coordinated shutdown
A producer sends messages through a send-only channel while watching a receive-only done channel. On shutdown, the receiver signals done; the producer logs completion, closes the message channel, and exits. section 5.3.2
