Golang, race condition with local map

Issue

I don’t seem to totally understand maps in Go.

I have this code:

fetch := map[string]int{some data}

for condition {
    fetchlocal := map[string]int{}

    for key, value := range fetch {
        if condition {
            fetchlocal[key] = value
        }
    }

    go threadfunc (fetchlocal)
}

Now wherever the threadfunc function uses the fetchlocal variable Go (go -race) says warning: data race. I also got a few panics already. But why? The fetchlocal variable isn’t used by any other goroutine.

Can someone enlighten me, please?

Solution

I’m assuming your fetch := map[string]int{some data} was actually supposed to be: fetch := map[string][]int{..some data..}.

For this to be a race threadfunc must be changing a value within fetchlocal or something else must be changing the value within fetch.

This is to say a slice is a actually:

type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}

When you are copying the elements from one map to another you are not doing a deep copy of the slices (you are just creating a new struct with the same Data,Len,Cap), that is so say fetch["foo"].Data == fetchlocal["foo"].Data.

Therefore you can say fetch[someExistingKey] = someNewValue and this will not race with threadfunc, but if you say fetch[someExistingKey][x] == foobar or fetchlocal[someExistingKey][x] == foobar the race will be on.

If fetchlocal needs to mutated by threadfunc you could change your inner loop to look like:

for key, value := range fetch {
    if condition {
        newVal := make([]int, len(value))
        copy(newVal, val)
        fetchlocal[key] = newVal
    }
}

Or alternatively, do the copy inside threadfunc as needed before mutating.

P.S. If you shared your actual threadfunc or code that is modifying fetch while these two loops are running, we will be able to help more.

Answered By – voidlogic

Answer Checked By – Clifford M. (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.