1 回答
TA贡献1802条经验 获得超5个赞
更新:
但是当我将映射的值类型更改为 int 或 string 时,没有数据竞争。
我进一步测试了你的代码。将映射的值类型更改为 int 或 string 会继续产生竞争条件。尝试while在你的 shell 上循环运行它,你会明白我的意思:
$ while true; do go run -race main.go; done
值类型之间不应该有任何差异。
正如竞态检测器所报告的,有两种不同的竞态条件。第一场比赛(您已修复)发生在i第 54 行的读取 (of ) 和第i51 行的写入 (to ) 之间。发生这种情况是因为您的 goroutine 闭包包含对 的引用,该引用由goroutine中的循环i更改. 您可以通过摆脱或传递给您的闭包来解决它,如下所示:formainprintln(">>", i)i
for i := 0; i < 4; i++ {
go func(index int) {
time.Sleep(2 * time.Second)
println(">>", index)
go m.Add("uz", City{"CityMakon"})
go m.Add("uzb", City{"CityMakon"})
}(i)
}
第二个竞争条件发生在第 37 行 ( m.Data[id] = h) 的赋值和第 25 行 ( ) 的删除之间delete(m.Data, i)。竞态检测器将此标记为竞态条件,因为它不能保证您的代码上的Happen Before约束。您可以通过以下任一方式解决此问题:
锁定delete语句:
m.Lock()
delete(m.Data, i)
m.Unlock()
或者,将Round()方法中的两种情况提取为两种方法,覆盖通道:
func (m *Map) Round() {
for i, v := range m.Data {
fmt.Println("-----", v)
delete(m.Data, i)
}
}
func (m *Map) Done() {
for range done {
println("bye")
break
}
}
func main() {
// ...
go Round()
go Done()
}
- 1 回答
- 0 关注
- 228 浏览
添加回答
举报