Race-free doesn’t mean deterministic

In this article about the Go race detector, I emphasize that violating the Memory model with unprotected concurrent accesses is a serious error.

I must add that fixing the data races doesn’t make a program execution trace deterministic. There can still be “races” in the sense of “first goroutine that takes a lock accesses first”, in an order that can’t be predicted.

Consider this program:

The race detector doesn’t emit any warning during its execution, as the write accesses to a are properly serialized thanks to the mutex mu.

$ go run -race not-racy.go

However, 2 goroutines are effectively racing to access the shared variable a. The lock guarantees that one of the accesses will always happen-before the other access. The specific order of the accesses may change the next time the program is executed.

Possible correct execution. Prints 33.
Possible correct execution. Prints 22.

In the two cases, the following unfortunate situation was successfully avoided:

Without a mutex, the concurrent writes would be a race condition.