A deadlock is a concurrency failure in which goroutines cannot make progress because they wait for events that cannot occur. In Go, sending to an unbuffered channel blocks until another goroutine receives; a listener that waits forever after all publishers stop eventually produces a deadlock error. section 9.3.4
A concurrent maze solver can deadlock in several closely related ways:
- Send the initial path before starting a receiver on an unbuffered channel; the send blocks immediately. section 9.3.4
- Keep listening after every worker has stopped publishing; Go reports that all goroutines are asleep. section 9.3.4
- Stop the listener when one worker finds the solution while other explorers still publish; their sends eventually fill the channel and block. section 9.4
- Send one quit message without stopping every explorer; remaining workers can still attempt blocking sends to a channel nobody reads. section 9.5.2
Prevent the failure by coordinating shutdown. A quit channel gives workers a shared stop signal; closing it broadcasts completion because reads from a closed channel always return. Workers should check quit before exploring and select between quitting and publishing, while a WaitGroup lets the listener wait for active explorers. section 9.5.2
Stopping maze exploration safely
When a worker finds the treasure, record the solution under a mutex and signal shutdown. Each explorer then selects between receiving from quit and sending its next branch: a closed quit channel lets it return instead of publishing work that no goroutine will consume. section 9.5.2
Listing 9.28 explore.go: Exploring only if the treasure isn’t found
func (s *Solver) explore(pathToBranch *path) {
// ...
for _, candidate := range candidates[1:] {
branch := &path{previousStep: pathToBranch, at: candidate}
select {
// s.quit returns a zero value only when the channel was closed
case <-s.quit:
log.Printf("I'm an unlucky branch, someone else found the treasure, I give up at position %v.", pos)
return
case s.pathsToExplore <- branch:
// continue execution after the select block
}
}
Inspect the worker loop that stops exploring when the quit channel closes and otherwise publishes the next branch. section 9.5.2














