A data race occurs when concurrent execution contexts access the same memory and at least one access writes without adequate synchronization. Two simultaneous writes to one cache entry are a race, even when tests sometimes pass. section 7.3.2 section 9.6.1
Detect and correct races with a practical workflow:
- Run independent subtests with t.Parallel() to exercise concurrent execution. section 7.3.2
- Run go test -race . to ask Go’s race detector to identify conflicting accesses and show their stack traces. section 7.3.3
- Protect shared state with a mutex placed beside the data it protects, and defer Unlock() immediately after Lock(). section 7.3.4 section 7.6
- Use RWMutex only when read concurrency and measured performance justify its additional complexity; a clean race-detector run is not proof that every race is absent. section 7.3.4 section 7.6
Parallel cache writes
Create one cache, then run two parallel subtests that both call Upsert(6, ...) with different values such as "six" and "kuus". A normal test run may appear successful; go test -trimpath -race . reports the conflicting writes and shows that the cache is not thread safe. section 7.3.2 section 7.3.3
> go test --trimpath -race .
==================
WARNING: DATA RACE
Write at 0x00c0000a53e0 by goroutine 13:
runtime.mapassign_fast64()
runtime/map_fast64.go:93 +0x0
learngo-pockets/genericcache.(*Cache[...]).Upsert()
learngo-pockets/genericcache/cache.go:28 +0x124
learngo-pockets/genericcache_test.TestCache_Parallel.func1()
learngo-pockets/genericcache/cache_test.go:73 +0x97
learngo-pockets/genericcache_test.TestCache_Parallel.func2()
learngo-pockets/genericcache/cache_test.go:74 +0x47
Previous write at 0x00c0000a53e0 by goroutine 20:
runtime.mapassign_fast64()
runtime/map_fast64.go:93 +0x0
learngo-pockets/genericcache.(*Cache[...]).Upsert()
learngo-pockets/genericcache/cache.go:28 +0x124
learngo-pockets/genericcache_test.TestCache_Parallel.func1()
learngo-pockets/genericcache/cache_test.go:73 +0x97
learngo-pockets/genericcache_test.TestCache_Parallel.func2()
learngo-pockets/genericcache/cache_test.go:74 +0x47
Inspect a representative race-detector report showing two goroutines writing through Cache.Upsert at the same map location. section 7.3.3
Listing 7.11 cache.go: Caching with a Mutex
type Cache[K comparable, V any] struct {
mu sync.Mutex
data map[K]V
}
Inspect the cache structure with a mutex stored next to its protected data map. section 7.3.4



