How to stop gorutin

I have a goroutine that calls a method and passes the return value through a pipe:

ch := make(chan int, 100) go func(){ for { ch <- do_stuff() } }() 

How to stop such a goroutine?

+85
go goroutine channels
Jul 24 '11 at 15:05
source share
6 answers

EDIT: I wrote this answer in a hurry before I realized that your question is about sending values ​​to Chan inside Goroutine. The approach below can be used either with an additional channel, as suggested above, or with the fact that you already have a bi-directional channel, you can use only one ...

If your subroutine exists solely to process elements coming from the vat, you can use the built-in close function and a special form of reception for channels.

That is, as soon as you finish sending items to the channel, you close it. Then, inside your procedure, you get an additional parameter for the receive statement, which indicates whether the channel has been closed.

Here is a complete example (a waiting group is used to make sure that the process continues until the program terminates):

 package main import "sync" func main() { var wg sync.WaitGroup wg.Add(1) ch := make(chan int) go func() { for { foo, ok := <- ch if !ok { println("done") wg.Done() return } println(foo) } }() ch <- 1 ch <- 2 ch <- 3 close(ch) wg.Wait() } 
+46
Nov 11 '11 at 19:19
source share

Typically, you pass a goroutine a channel (possibly a separate one). This signal channel is used to enter a value when you want the goroutine to stop. Gorotinsky polls that regularly take place. As soon as it detects a signal, it shuts down.

 quit := make(chan bool) go func() { for { select { case <- quit: return default: // Do other stuff } } }() // Do stuff // Quit goroutine quit <- true 
+101
Jul 24 '11 at 15:39
source share

You cannot kill goroutin from without. You can signal goroutine to stop using the channel, but there is no handle in goroutines to do any meta control. The Vorotins are designed to solve problems together, so killing a person who behaves badly will almost never be an adequate response. If you need insulation for reliability, you probably want to complete the process.

+26
Jul 28 '11 at 7:40
source share

Typically, you can create a channel and receive a stop signal in the program.

In this example, there are two ways to create a channel.

  1. channel

  2. context . In the example, I have context.WithCancel demo context.WithCancel

First demo, use channel :

 package main import "fmt" import "time" func do_stuff() int { return 1 } func main() { ch := make(chan int, 100) done := make(chan struct{}) go func() { for { select { case ch <- do_stuff(): case <-done: close(ch) return } time.Sleep(100 * time.Millisecond) } }() go func() { time.Sleep(3 * time.Second) done <- struct{}{} }() for i := range ch { fmt.Println("receive value: ", i) } fmt.Println("finish") } 

Second demo, use context :

 package main import ( "context" "fmt" "time" ) func main() { forever := make(chan struct{}) ctx, cancel := context.WithCancel(context.Background()) go func(ctx context.Context) { for { select { case <-ctx.Done(): // if cancel() execute forever <- struct{}{} return default: fmt.Println("for loop") } time.Sleep(500 * time.Millisecond) } }(ctx) go func() { time.Sleep(3 * time.Second) cancel() }() <-forever fmt.Println("finish") } 
+9
Nov 15 '17 at 8:47
source share

I know that this answer has already been accepted, but I thought I would give up my 2 cents. I like to use the tomb . This is basically a supported exit channel, but it does nice things, like returning any errors. Under control under control is still checking for the presence of remote signals. Afaik it is impossible to get an "id" from a goroutine and kill it if it behaves badly (i.e. Stuck in an infinite loop).

Here is a simple example that I tested:

 package main import ( "launchpad.net/tomb" "time" "fmt" ) type Proc struct { Tomb tomb.Tomb } func (proc *Proc) Exec() { defer proc.Tomb.Done() // Must call only once for { select { case <-proc.Tomb.Dying(): return default: time.Sleep(300 * time.Millisecond) fmt.Println("Loop the loop") } } } func main() { proc := &Proc{} go proc.Exec() time.Sleep(1 * time.Second) proc.Tomb.Kill(fmt.Errorf("Death from above")) err := proc.Tomb.Wait() // Will return the error that killed the proc fmt.Println(err) } 

The result should look like this:

 # Loop the loop # Loop the loop # Loop the loop # Loop the loop # Death from above 
+8
Nov 23 '13 at 18:34
source share

Personally, I would like to use the range on the channel in the program:

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

Dave wrote a great post about this: http://dave.cheney.net/2013/04/30/curious-channels .

+5
May 14 '14 at 6:05
source share



All Articles