-1

I have a pool of goroutines which I want to kill a specific one of them from outside.

Thanks for your help

Omid Tavakoli
  • 156
  • 2
  • 5
  • The routine must terminate on its own. It can either return from the function that was invoked via the `go` keyword, or call `runtime.Goexit()`. – torek Jan 06 '20 at 07:16

3 Answers3

3

You cannot "kill" a goroutine. You can use one of the synchronizations primitives, or the context to tell the goroutine that you want it to end.

ctx,cancel:=context.WithCancel(context.Background())
go  func(ctx context.Context) {
   for {
      select {
         case <-ctx.Done():
           return 
         default
       }
       // Do stuff
     }
}(ctx) 
...
// Tell that goroutine to stop
cancel()

You can use sync.atomic as well:

die:=make([]int32,nGoroutines)

go func(i int) {
   if atomic.LoadInt32(&die[i])==1 {
       return
   }
   // Do stuff
   if atomic.LoadInt32(&die[i])==1 {
       return
   }
   // Do more stuff
}(0) // 0'th goroutine

...
// Tell goroutine n to stop
atomic.StoreInt32(&die[n],1)
Burak Serdar
  • 46,455
  • 3
  • 40
  • 59
1

I found an answer. There is a concept named Context which carries deadlines, cancelation signals, and other request-scoped values across API boundaries and between processes. This is sample codes:

type Job struct {
    ID int
    Context context.Context
    Cancel context.CancelFunc
}
var jobs = make(map[int] Job)

func worker(ctx context.Context, index int) {
   fmt.Printf("starting job with id %d\n", index)
   <-ctx.Done()
}

func main() {
 var err error

 id := 0
 r := gin.Default()

 r.POST("/start", func(c *gin.Context) {
    var job Job
    err := json.NewDecoder(c.Request.Body).Decode(&job)
    if err != nil{ fmt.Println(err)}
    ctx, cancel := context.WithCancel(context.Background())
    job.ID = id
    job.Context = ctx
    job.Cancel = cancel
    jobs[job.ID] = job
    c.JSON(http.StatusOK, gin.H{"message": "job received"})
    go worker(ctx, job.ID)
    id ++
 })

 r.GET("/cancel/:id", func(c *gin.Context) {
    id := c.Param("id")
    idInt, err := strconv.Atoi(id)
    if err != nil {fmt.Println(err)}
    jobs[idInt].Cancel()
 })

  err = endless.ListenAndServe(":8080", r)
  if err != nil{ fmt.Printf("Could not run server : %v", err.Error())}
 }
Omid Tavakoli
  • 156
  • 2
  • 5
  • 1
    This is a sample of terminating goroutine using API – Omid Tavakoli Jan 06 '20 at 07:28
  • 1
    If `worker` calls some function, and the function has not returned, the worker will not exit. The function itself needs to check now and then whether it should exit. When the function is done, it can just return; there's no need to wait on the `ctx.Done()` channel, as nothing will ever be sent: it will only be closed. – torek Jan 06 '20 at 08:18
0

You could use a channel

endRoutine:=  make(chan bool)
go func() {
    <-endRoutine
}()

//To end one thread waiting on the channel
endRoutine<-true

https://play.golang.org/p/IRARfywOLZX

If you are processing data in a loop and need to check if you should exit on each iteration, you can use a switch

go func() {
    for {
        switch {
             case <-endRoutine:
              return //exit
              default:
              break
        }
   }
}()

https://play.golang.org/p/18eOHpilnFi

pigeonhands
  • 3,066
  • 15
  • 26