Go

What does this program print?

Question 233HardGo 1.22 to 1.25
var done bool
var msg string

func setup() {
	msg = "hello"
	done = true
}

func main() {
	go setup()
	for !done {
	}
	fmt.Println(msg)
}

No output is guaranteed. This is a data race, and several things can happen:

  • The compiler may hoist the load of done out of the loop, since nothing in the loop body can change it. The loop then never ends.
  • If the loop does exit, main may still print an empty string. Nothing orders msg = "hello" before the read, so the writes can be observed out of order.
  • go run -race reports the race.

The fix is to create a real happens-before edge:

var done atomic.Bool
var msg string

func setup() {
	msg = "hello"
	done.Store(true) // publishes msg
}

func main() {
	go setup()
	for !done.Load() {
		runtime.Gosched()
	}
	fmt.Println(msg) // guaranteed "hello"
}

Better still, avoid spinning altogether: close a channel, or use a sync.WaitGroup. The atomic store and load publish msg because the write to msg happens-before Store, which happens-before the Load that observes it.

More on Concurrency Patterns & sync

All 38 Concurrency Patterns & sync questions