Is reading a variable without atomic conflicts with atomic.CompareAndSwap
? I have the following code:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
x := int32(0)
for i := 0; i < 100000; i++ {
n := int32(0)
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
atomic.CompareAndSwapInt32(&n, 1, 2)
wg.Done()
}()
go func() {
x += n
wg.Done()
}()
wg.Wait()
}
fmt.Println(x)
}
It’s very simple program: there are two goroutines, one of them call atomic.CompareAndSwap()
on n
. The other one reads n
(without atomic). Running this program with go run -race main.go
gives this output:
==================
WARNING: DATA RACE
Read at 0x00c00001413c by goroutine 8:
main.main.func2()
/tmp/atomictest/main.go:20 +0x59
Previous write at 0x00c00001413c by goroutine 7:
sync/atomic.CompareAndSwapInt32()
/home/jauhararifin/.gvm/gos/go1.21/src/runtime/race_amd64.s:310 +0xb
sync/atomic.CompareAndSwapInt32()
<autogenerated>:1 +0x18
Goroutine 8 (running) created at:
main.main()
/tmp/atomictest/main.go:19 +0x4a
Goroutine 7 (running) created at:
main.main()
/tmp/atomictest/main.go:15 +0x17c
==================
A data race is detected there because I read n
(without atomic) concurrently with atomic.CompareAndSwap(&n, ..., ...)
. Notice that I set the CAS operation to always fail.
This is understandable because I don’t use atomic operation when reading n
. But I read the go sync.Mutex
implementation:
func (m *Mutex) Lock() {
// Fast path: grab unlocked mutex.
if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
if race.Enabled {
race.Acquire(unsafe.Pointer(m))
}
return
}
// Slow path (outlined so that the fast path can be inlined)
m.lockSlow()
}
func (m *Mutex) lockSlow() {
var waitStartTime int64
starving := false
awoke := false
iter := 0
old := m.state
...
}
As you can see, there is a possible concurrent access on the m.state
. In the fast path, one goroutine can execute CAS on &m.state
. Concurrently, another goroutine can execute old := m.state
in the slow path. But having concurrent Lock()
with -race
flag doesn’t show any report of data race. How is this possible?