liveBook · Manning

Safe channel closing

As explained in Go in Practice, Second Edition

Safe channel closing is the practice of coordinating channel closure so that no goroutine sends on the channel after it is closed and all related goroutines can terminate.

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

How Go in Practice, Second Edition covers it

How deep it goes
Demonstrates a panic-producing close, sender-side closure, and a done-channel protocol with runnable Go listings.
Examples
Uses an improper timeout close, a sender that closes its channel, and a separate done channel for coordinated termination.
What it assumes
Assumes familiarity with Go channels, goroutines, select statements, and basic channel sends and receives.
What you can do after
Operate a coordinated shutdown by notifying the sender, closing from the sender, and returning from the goroutine.
How it connects
Connects channels with goroutines, senders, receivers, select, timeouts, and directional channel types.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Practice, Second Edition. The section links point to the parts of the book it draws on.