go - 为什么要报告这种数据竞赛?
问题描述
我用“-race”标志构建了以下代码并运行它(go version go1.14.1 linux/amd64),报告了一些数据竞争(见下文)。有时只报告了一场数据竞赛,有时报告了三场。第 24 行和第 35 行之间的数据竞争是可以理解的,但我不明白为什么会报告第 24 行和第 40 行之间的数据竞争。
1 package main
2
3 import (
4 "sync"
5 )
6
7 var (
8 m = make(map[string]string)
9 pm = &m
10 updateLock = sync.RWMutex{}
11 )
12
13 func main() {
14 wg := &sync.WaitGroup{}
15 wg.Add(2)
16 go func() {
17 defer wg.Done()
18 handle()
19 }()
20
21 go func() {
22 defer wg.Done()
23 //updateLock.RLock()
24 if _, ok := (*pm)["test"]; ok {
25 }
26 //updateLock.RUnlock()
27 }()
28 wg.Wait()
29 }
30
31 func handle() {
32 newMap := make(map[string]string)
33 update(&newMap)
34 updateLock.Lock()
35 pm = &newMap
36 updateLock.Unlock()
37 }
38
39 func update(ptrMap *map[string]string) {
40 (*ptrMap)["test"] = "test"
41 }
我认为在第 40 行handle
传递给update
要修改的函数的函数中创建的映射与在第 24 行读取的映射不同。指针替换发生在更新完成后,那么为什么会有这样的数据竞争:
==================
WARNING: DATA RACE
Read at 0x00c000070030 by goroutine 7:
runtime.mapaccess2_faststr()
/home/vagrant/.go/src/runtime/map_faststr.go:107 +0x0
main.main.func2()
/vagrant/go_projects/src/learn/race/main.go:24 +0xd1
Previous write at 0x00c000070030 by goroutine 6:
runtime.mapassign_faststr()
/home/vagrant/.go/src/runtime/map_faststr.go:202 +0x0
main.update()
/vagrant/go_projects/src/learn/race/main.go:40 +0xba
main.handle()
/vagrant/go_projects/src/learn/race/main.go:33 +0x7f
main.main.func1()
/vagrant/go_projects/src/learn/race/main.go:18 +0x5f
Goroutine 7 (running) created at:
main.main()
/vagrant/go_projects/src/learn/race/main.go:21 +0xc4
Goroutine 6 (finished) created at:
main.main()
/vagrant/go_projects/src/learn/race/main.go:16 +0xa2
==================
PS 当第 23 行和第 26 行未注释时,比赛就消失了。
解决方案
handle()
正在写入pm
(指针pm
,而不是映射内容),而第二个 goroutine 正在读取pm
而没有锁定。这就是报告比赛的原因。当您pm
使用锁访问时,goroutine 在写入期间无法读取pm
。
当 goroutine 从 中读取时pm
,pm
有可能尚未初始化。
竞争检测器检测对地图的锁定/解锁读/写访问。读取 goroutine 是在没有锁的情况下从 map 中读取,而 write goroutine 是在没有锁的情况下写入同一个 map。这就是种族检测器所抱怨的。
推荐阅读
- npm - gh-pages 不显示网站
- docker - 在 docker-compose 文件中映射端口不起作用。网络不可达
- laravel - 如何在虚拟主机上上传 laravel 项目?
- javascript - 用于从 Google 表格中的非规范化数据创建规范化数据的 Google Apps 脚本
- r - 如何在 R 中基于离屏(位图)图形创建“交互式”图形设备?
- python - 使用 pandas 重置 CSV 的列位置
- java - conn.prepareStatement(sql) 上的 java.lang.NullPointerException
- json - 如何将 REST API 调用返回的 JSON 解析为 JAX-RS 中的对象集合?
- swift - 如何检索firebase数据库值以计算平均值
- c++ - 为什么范围的算法与 std 的迭代器不兼容?