Skip to content

About memory ordering guarantees made by atomic operations in Go

Go101 edited this page Jul 11, 2018 · 5 revisions

Does the following program always print 789?

package main

import "fmt"
import "runtime"

func main() {
	var a, b int32 = 0, 0

	go func() {
		a = 789
		b = 123
		runtime.Gosched()
	}()

	for {
		if b == 123 {
			fmt.Println(a) // always print 789?
			return
		}
	}

	select {}
}

The answer is no. Besides there are data races existing in the above program, Go 1 memory model clearly states that the order of the two writes to (and reads from) a and b are not guaranteed to be the same as their literal order in code.

Then does the following another program always print 789?

package main

import "fmt"
import "runtime"
import "sync/atomic"

func main() {
	var a, b int32 = 0, 0

	go func() {
		atomic.StoreInt32(&a, 789)
		atomic.AddInt32(&b, 123)
		runtime.Gosched()
	}()

	for {
		if atomic.LoadInt32(&b) == 123 {
			fmt.Println(atomic.LoadInt32(&a)) // always print 789?
			return
		}
	}

	select {}
}

Go 1 memory model doesn't give a clear answer for this question. Go core team members Keith Randall and Ian Lance Taylor think the answer is yes, at least for the current standard Go compiler (gc v1.10) and gccgo (v8.1). Many standard packages rely on the order guarantee made by atomic operations.

However, none of official Go documentations make the guarantee that the write to a will happen before the write to b and the read from b will happen before the read from a. In other words, for simplicity, unlike C/C++, Go atomic operations are not entangled with memory ordering.

Should custom user code depends on the undocumented memory order guarantees made by Go atomic operations? Don't do this! Otherwise, the behavior of your code may change when it is compiled by other future possible Go compilers or later versions of gc and gccgo compilers.

BTW, there is a proposal by Russ Cox to suggest writing down the guarantees in official documentations. But it looks Rob Pike thinks it is unnecessary. I guess Rob Pike worries about introducing memory ordering guarantees to atomic operations will complicate the atomic operation usages much, whereas Go is a language for ease of using.

You can’t perform that action at this time.