Go

Does this counter give the right answer with GOMAXPROCS=1? What about counter++ in general?

Question 235MediumGo 1.22 to 1.25
func main() {
	runtime.GOMAXPROCS(1)
	var n int
	var wg sync.WaitGroup
	for range 1000 {
		wg.Go(func() { n++ })
	}
	wg.Wait()
	fmt.Println(n)
}

It will often print 1000 with one P, but that is not guaranteed and the program is still a data race that -race flags. The reasons:

  • n++ is a load, an add and a store. The runtime can preempt a goroutine between any of them; asynchronous preemption has existed since Go 1.14.
  • The memory model speaks about happens-before, not about how many CPUs you have. With no synchronization the compiler may keep n in a register.
  • The race detector reports it no matter what GOMAXPROCS is.

Correct versions:

var n atomic.Int64
wg.Go(func() { n.Add(1) })

// or confine the state to one goroutine and send results over a channel,
// or protect n with a sync.Mutex.

What the interviewer is looking for: correctness must never depend on scheduler details. GOMAXPROCS=1 hides races; it does not remove them.

More on Concurrency Patterns & sync

All 38 Concurrency Patterns & sync questions