I am currently learning the Go programming language and I am now experimenting with the atomic package.
In this example, I am spawning a number of Goroutines that all need to increment a package level variable. There are several methods to avoid race conditions but for now I want to solve this using the atomic
package.
When running the following code on my Windows PC (go run main.go
) the results are not what I expect them to be (I expect the final result to be 1000). The final number is somewhere between 900 and 1000. When running the code in the Go Playground the value is 1000.
Here is the code I am using: https://play.golang.org/p/8gW-AsKGzwq
var counter int64
var wg sync.WaitGroup
func main() {
num := 1000
wg.Add(num )
for i := 0; i < num ; i++ {
go func() {
v := atomic.LoadInt64(&counter)
v++
atomic.StoreInt64(&counter, v)
// atomic.AddInt64(&counter, 1)
// fmt.Println(v)
wg.Done()
}()
}
wg.Wait()
fmt.Println("final", counter)
}
go run main.go
final 931
go run main.go
final 960
go run main.go
final 918
I would have expected the race detector to give an error, but it doesn't:
go run -race main.go
final 1000
And it outputs the correct value (1000).
I am using go version go1.12.7 windows/amd64
(latest version at this moment)
My questions:
- Why is the race detector not giving an error, but am I seeing different values when running the code without the race detector?
- My theory why the Load/Store combination is not working is that the two atomic calls are not atomic as a whole. In this case I should be using the
atomic.AddInt64
method, is that right?
Any help would be greatly appreciated :)