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!

Recommended Readings:

+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.