Exiting Multiple Goroutines Simultaneously

Posted

The ability to close channels (using Go’s builtin close() function) forms the basis of a useful pattern in Go: using a single channel to exit multiple goroutines.

Let’s say we have launched a variable number of goroutines in the background as follows:

shutdown := make(chan struct{})
done := make(chan int)

for i := 0; i < n; i++ {
	i := i
	go func() {
		select {
		case <-shutdown:
			done <- i
		}
	}()
}

Once started, each goroutine will wait for a signal from a single shutdown channel before exiting. We would like to signal all n goroutines to be shut down at once in the most elegant way possible. To do so, we can make use of the fact that receiving on a closed channel will never block. Simply by closing the shutdown channel, we can signal all goroutines to “unblock,” causing them to immediately exit. A complete example is given below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import (
	"fmt"
	"time"
)

var (
	shutdown = make(chan struct{})
	done     = make(chan int)
)

func main() {
	const n = 5

	// Start up the goroutines...
	for i := 0; i < n; i++ {
		i := i
		go func() {
			select {
			case <-shutdown:
				done <- i
			}
		}()
	}

	time.Sleep(2 * time.Second)

	// Close the channel. All goroutines will immediately "unblock".
	close(shutdown)

	for i := 0; i < n; i++ {
		fmt.Println("routine", <-done, "has exited!")
	}
}

You can also view and run the above example on the Go Playground.

Let me know if you found this pattern helpful in the comments below, and don’t forget to +1 this post!

+1 this blog!

Go Design Patterns is a website for developers who wish to better understand the Go programming language. The tutorials here emphasize proper code design and project maintainability.

Find a typo?

Submit a pull request! The code powering this site is open-source and available on GitHub. Corrections are appreciated and encouraged! Click here for instructions.