Why does this code cause data race?

試著忘記壹切 提交于 2019-12-01 22:55:22

The requirements to have a data race are:

  1. Multiple goroutines accessing the same resource (e.g. a variable) concurrently.
  2. At least one of those accesses is a write.
  3. The accesses are uncynchronized.

In your code all 3 requirements are met:

  1. You have the main goroutine accesssing m1, and the one you start in it also accesses m1. The main goroutine accesses it after the other goroutine has been launched, so they are concurrent.
  2. The main goroutine writes m1 in line #17: m1 = m2.
  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!