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 關注
- 259 瀏覽
添加回答
舉報