0

i have to invoke goroutuine /thread from a loop. Because of the loop, there are many go routines executes in parallel. If any routine/thread executed successfully, then i have to stop all other thread/routine.

Is there any way to implement this?

sumith
  • 29
  • 1
  • 7

3 Answers3

2

You can use quit channels in addition to context as answered by Burak.


package main

import (
    "fmt"
    "math/rand"
    "time"
)

func foo(channel, quit chan string, i int) {

    channel <- fmt.Sprintf("goroutine %d started!", i)
    for {
        rand.Seed(time.Now().UnixNano())
        time.Sleep(time.Duration(rand.Intn(500)+500) * time.Millisecond)
        quit <- fmt.Sprintf("goRoutine %d completed!", i)
    }
}
func main() {

    channel := make(chan string)
    quit := make(chan string)

    for i := 0; i < 3; i++ {
        go foo(channel, quit, i)
    }
    
    for {
        select {
        case update:= <-channel:
            fmt.Println(update)
        case quit:= <-quit:
            fmt.Println(quit)
            return
        }
    }
}

1

You can use a context:

ctx, cancel:= context.WithCancel(context.Background())
for ... {
   go func() {
      defer cancel() // cancel context once this goroutine ends
      doStuff(ctx)
   }()
}

You have to check context cancellation in the goroutines:

func doStuff(ctx context.Context) {
   ...
   if ctx.Err()!=nil {
       // Canceled, return
       return
   }
  ...
}

This will not guarantee that once the context is canceled other goroutines will end immediately, however it guarantees that, if you check for context cancellation correctly, all goroutines will end eventually.

Burak Serdar
  • 46,455
  • 3
  • 40
  • 59
0

You could use a context and an errgroup. Something along the lines of...

package main

import (
    "context"
    "fmt"
    "math/rand"
    "os"
    "time"

    "golang.org/x/sync/errgroup"
)

func doStuff(ctx context.Context, i int) error {
    count := 0
    for ctx.Err() == nil {
        // do the stuff
        time.Sleep(time.Millisecond * time.Duration(rand.Intn(500)))
        count++
        if count > 6 { // error condition
            fmt.Fprintf(os.Stdout, "%v reached count %v\n", i, count)
            return fmt.Errorf("Error %v, count %v\n", i, count)
        }
    }
    fmt.Fprintf(os.Stdout, "Killed %v @ count %v\n", i, count)
    return ctx.Err()
}

func main() {
    rand.Seed(int64(time.Now().Nanosecond()))
    ctxWc, _ := context.WithCancel(context.Background())
    g, ctx := errgroup.WithContext(ctxWc)
    for i := 0; i < 5; i++ {
        i := i
        g.Go(func() error {
            return doStuff(ctx, i)
        })
    }
    err := g.Wait()
    fmt.Println("The End")
    if err != nil {
        fmt.Println(err)
    }
}
Olaf Bogus
  • 26
  • 3