1 package main
2
3 import "time"
4
5 func main() {
6 m1 := make(map[string]int)
7 m1["hello"] = 1
8 m1["world"] = 2
9 go func() {
10 for i := 0; i < 100000000; i++ {
11 _ = m1["hello"]
12 }
13 }()
14 time.Sleep(100 * time.Millisecond)
15 m2 := make(map[string]int)
16 m2["hello"] = 3
17 m1 = m2
18 }
I run command go run --race with this code and get:
==================
WARNING: DATA RACE
Read at 0x00c420080000 by goroutine 5:
runtime.mapaccess1_faststr()
/usr/local/go/src/runtime/hashmap_fast.go:208 +0x0
main.main.func1()
/Users/meitu/test/go/map.go:11 +0x80
Previous write at 0x00c420080000 by main goroutine:
runtime.mapassign()
/usr/local/go/src/runtime/hashmap.go:485 +0x0
main.main()
/Users/meitu/test/go/map.go:16 +0x220
Goroutine 5 (running) created at:
main.main()
/Users/meitu/test/go/map.go:13 +0x1aa
==================
m1 and m2 are different variables,why do line 16 and line 11 cause data race?
My go version is 1.8. I guess that is some compile optimization, and somebody can tell me about it? Thank you very much.
The requirements to have a data race are:
In your code all 3 requirements are met:
m1, and the one you start in it also accessesm1. The main goroutine accesses it after the other goroutine has been launched, so they are concurrent.m1in line #17:m1 = m2.Therefore it's a data race.
The obvious data race is between lines #11 reading
m1, and line #17 writingm1.But! Since line #17 assigns
m2tom1, then when/if the launched goroutine continues to run, it attempts to readm1which may now be the value ofm2because we assignedm2tom1. What does this mean? This introduces another data race writingm2and readingm1.That is after line #17 if the program does not end immediately (it may, but not necessarily), then the launched goroutine attempts to read from
m1which is nowm2which was last written in line #16, so this explains the "conflict" between lines #11 and #16.The full
go run -raceoutput is as follows: