Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

index out of range goroutine golang

Tags:

go

goroutine

Index out of range error where it seems impossible in goroutine generated by for loop

This is the go code I am executing. The problem is that an index out of range error is yielded inside the evaluation of one of the arguments to countlinks call in a goroutine. The length of the slice we're iterating against is ALWAYS 2. Based on my understanding of for loops in go, i should never evaluate to 2 (yielding index out of range in expression grph.entryPoints[i]), and yet it is. Please, tell me how I am crazy.

func main() {
    grph := structures.ConfigGraphDefault()
    counter := structures.NewCounter()
    queue := structures.NewQueue()
    tracker := structures.NewTracker()
    fmt.Printf("entries: %v\nnodes: %v\n", grph.EntryPoints, grph.Nodes)
    wg := sync.WaitGroup{}
    fmt.Println(len(grph.EntryPoints))
    // this will always evaluate to 2
    l := len(grph.EntryPoints)
    for i := 0; i < l; i++ {
        wg.Add(1)
        go func() {
            fmt.Printf("index: %v, length of slice: %v\n", i, len(grph.EntryPoints))
            structures.CountLinks(&grph, counter, queue, tracker, grph.EntryPoints[i], i)
            wg.Done()
        }()
    }
    wg.Wait()
    fmt.Printf("counter: %v", counter.GetCounts())
}
like image 631
sloan-dog Avatar asked Dec 24 '22 09:12

sloan-dog


1 Answers

i does become 2, but only at the very end of the loop. But because your goroutine function closes over i, it doesn't see the value of i at the time the goroutine was started, but the value of i at the time it executes. In other words, all your goroutines share the same variable i.

To fix this, one way is to copy i to a helper variable declared inside the loop body. A nicer way is to pass it as an argument to the goroutine:

    go func(i int) {
        fmt.Printf("index: %v, length of slice: %v\n", i, len(grph.EntryPoints))
        structures.CountLinks(&grph, counter, queue, tracker, grph.EntryPoints[i], i)
        wg.Done()
    }(i)
like image 89
Thomas Avatar answered Jan 02 '23 13:01

Thomas