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:
- Multiple goroutines accessing the same resource (e.g. a variable) concurrently.
- At least one of those accesses is a write.
- The accesses are uncynchronized.
In your code all 3 requirements are met:
- You have the main goroutine accesssing
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. - The main goroutine writes
m1in line #17:m1 = m2. - The accesses are not synchronized, you use no mutex or channels or anything like that (sleeping is not synchronization).
Therefore it's a data race.
The obvious data race is between lines #11 reading m1, and line #17 writing m1.
But! Since line #17 assigns m2 to m1, then when/if the launched goroutine continues to run, it attempts to read m1 which may now be the value of m2 because we assigned m2 to m1. What does this mean? This introduces another data race writing m2 and reading m1.
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 now m2 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:
==================
WARNING: DATA RACE
Write at 0x00c42000e010 by main goroutine:
main.main()
/home/icza/gows/src/play/play2.go:17 +0x22f
Previous read at 0x00c42000e010 by goroutine 5:
[failed to restore the stack]
Goroutine 5 (running) created at:
main.main()
/home/icza/gows/src/play/play2.go:9 +0x190
==================
==================
WARNING: DATA RACE
Read at 0x00c42007e000 by goroutine 5:
runtime.mapaccess1_faststr()
/usr/local/go/src/runtime/hashmap_fast.go:208 +0x0
main.main.func1()
/home/icza/gows/src/play/play2.go:11 +0x7a
Previous write at 0x00c42007e000 by main goroutine:
runtime.mapassign_faststr()
/usr/local/go/src/runtime/hashmap_fast.go:598 +0x0
main.main()
/home/icza/gows/src/play/play2.go:16 +0x1fc
Goroutine 5 (running) created at:
main.main()
/home/icza/gows/src/play/play2.go:9 +0x190
==================
==================
WARNING: DATA RACE
Read at 0x00c420080088 by goroutine 5:
main.main.func1()
/home/icza/gows/src/play/play2.go:11 +0x90
Previous write at 0x00c420080088 by main goroutine:
main.main()
/home/icza/gows/src/play/play2.go:16 +0x212
Goroutine 5 (running) created at:
main.main()
/home/icza/gows/src/play/play2.go:9 +0x190
==================
Found 3 data race(s)
exit status 66
Data race
A data race occurs when two goroutines access the same variable concurrently and at least one of the accesses is a write.
Instructions Reorder
compilers and processors may reorder the reads and writes executed within a single goroutine as far as the reordering does not change the behaviour within the routine, it doesn' ensure behaviour of other goroutines to be unaffected
m2["hello"] = 3
m1 = m2
Can be reordered to
m1 = m2
m2["hello"] = 3
That won't alter the behaviour of the main routine and thus race checking will consider that also for evaluating race condition. Now we have m2["hello"] = 3 causing the race condition and it prints out the same with its original line number
来源:https://stackoverflow.com/questions/46233680/why-does-this-code-cause-data-race