Go: Race Detector with ThreadSanitizer
Go provides a powerful tool to detect race conditions. This tool can be enabled by the flag -race
that you can use with your tests or during compilation.
Let’s create a simple example of data race and analyze how Go does the detection and what tool it uses. Our following program will increment a variable until it reaches the value 100k thanks to two goroutines:
var foo = 0
func main() {
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < 50000 ;i++ {
foo++
}
}()
go func() {
defer wg.Done()
for i := 0; i < 50000 ;i++ {
foo++
}
}()
wg.Wait() println(foo)
}
The result will always change due to the concurrency read/write on the variable. If you do not fully understand this example, I suggest you read the introduction to the race detector.
Race detector functions
In order to understand how Go internally manages the race condition detections, let’s generate the asm code thanks to the command go tool compile -S -race main.go
. Here is an extract of the output with the instructions related to foo++
:
(main.go:14) CALL runtime.raceread(SB)
(main.go:14) CALL runtime.racewrite(SB)
(main.go:16) CALL…