How to Stop a goroutine in Golang

Created
Modified

A signal channel

Typically, you pass the goroutine a (possibly separate) signal channel. That signal channel is used to push a value into when you want the goroutine to stop. The goroutine polls that channel regularly. As soon as it detects a signal, it quits.

package main

import (
  "fmt"
  "time"
)

func main() {

  done := make(chan bool)

  go func() {
    for {
      select {
      case <-done:
        fmt.Println("done")
        return
      default:
        // ...
      }
    }
  }()

  fmt.Println("A")
  time.Sleep(time.Millisecond)

  done <- true

}
$ go run main.go
A
done

Using close Function

To close a channel, we call the built-in close function:

package main

import (
  "fmt"
)

func main() {

  c1 := make(chan int)

  go func() {
    for {
      v, ok := <-c1
      if !ok {
        fmt.Println("done")
        return
      }
      fmt.Println(v)
    }
  }()

  c1 <- 1
  c1 <- 2
  close(c1)

  // panic: send on closed channel
  c1 <- 3

}
$ go run main.go
1
2
done
panic: send on closed channel

Use the context

Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.

package main

import (
  "context"
  "fmt"
)

func main() {

  c1 := make(chan int)
  ctx, cancel := context.WithCancel(context.Background())

  go func(ctx context.Context) {
    for {
      select {
      case <-ctx.Done():
        fmt.Println("done")
        return
      default:
        fmt.Println(<-c1)
      }

    }
  }(ctx)

  c1 <- 1
  c1 <- 2

  cancel()

  // fatal error:
  c1 <- 3

}
$ go run main.go
1
2
done
fatal error: all goroutines are asleep - deadlock!

Related Tags