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.m1
in 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
m2
tom1
, then when/if the launched goroutine continues to run, it attempts to readm1
which may now be the value ofm2
because we assignedm2
tom1
. What does this mean? This introduces another data race writingm2
and 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
m1
which is nowm2
which was last written in line #16, so this explains the "conflict" between lines #11 and #16.The full
go run -race
output is as follows: