GO / CHAPTER 13

Cancellation and bounded concurrent work

Advanced

Make workers stop cooperatively and assign channel ownership.

By the end of this chapter

  • Observe context cancellation
  • Separate cancellation from completion
  • Assign channel closing to the sender side

The idea

A context carries a cancellation signal and optionally a deadline through a call chain. Cancellation is cooperative: work stops only when the code or a called operation observes the signal. A worker can select between sending a result and receiving from ctx.Done, preventing an abandoned receiver from trapping it forever. Always define how callers learn whether work completed or was canceled.

Cancellation does not wait for every goroutine to exit. Use an explicit completion mechanism when shared resources must remain available until workers finish. Channel ownership also matters: the sender side should coordinate closing after all sends are finished. Receiving from a closed channel remains valid and reports completion through the second receive result; sending to a closed channel panics. Avoid tests that assume one scheduler ordering when several outcomes are permitted.

Go example
package main
import ("fmt"; "context")
func main(){ ctx,cancel:=context.WithCancel(context.Background()); cancel(); <-ctx.Done(); fmt.Println(ctx.Err()==context.Canceled); ch:=make(chan int,1); ch<-7; close(ch); v,ok:=<-ch; fmt.Println(v,ok); _,ok=<-ch; fmt.Println(ok) }
Result
true
7 true
false

Cancellation closes the Done channel. A closed buffered channel still yields queued data before receives report that no values remain.

Try it yourself

Design a worker send that can exit when the caller cancels instead of blocking forever.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

Who should close a channel used by several senders?