Go

What happens to goroutines that are already blocked on a channel when it is closed?

Question 218HardGo 1.22 to 1.25

closechan sets the closed flag under the channel lock, removes every waiting sudog from both recvq and sendq, and makes all of those goroutines runnable:

  • Blocked receivers wake up with the zero value and ok == false. On an unbuffered channel, or a buffered one that is empty, nothing is left to drain.
  • Blocked senders wake up and panic with send on closed channel, even though their send started before the close.
package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int)
	for i := range 3 {
		go func() {
			defer func() { fmt.Println(i, recover()) }()
			ch <- i // all three park here
		}()
	}
	time.Sleep(100 * time.Millisecond) // demo only: let them block
	close(ch)
	time.Sleep(100 * time.Millisecond)
}

This prints three lines like 1 send on closed channel, in any order. Without the recover, the first panic would crash the whole program.

Why interviewers ask: it shows why "the receiver closes to tell senders to stop" is wrong. Senders that are in flight at that moment crash. A close is only safe once no send can still happen, which is why the owner/single-closer rule exists and why stop signals go through a separate done channel or context.

More on Channels & select

All 38 Channels & select questions