亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Golang Data Race,退出狀態為 66

Golang Data Race,退出狀態為 66

Go
偶然的你 2022-01-17 17:47:38
我有以下代碼,并且正在進行數據競爭。Round 函數定期檢查運行刪除地圖內容的函數正如我在這里讀到的:從地圖中刪除數據是安全的,但我有數據競爭package mainimport (    "fmt"    "sync"    "time")type City struct {    ID string}type Map struct {    sync.RWMutex    Data map[string]City}var done = make(chan struct{})func (m *Map) Round() {    for {        select {        case <-time.After(2 * time.Second):            for i, v := range m.Data {                fmt.Println("-----", v)                delete(m.Data, i)            }        case <-done:            println("bye")            break        }    }}func (m *Map) Add(id string, h City) {    m.Lock()    m.Data[id] = h    m.Unlock()}func main() {    m := Map{}    m.Data = make(map[string]City)    m.Data["Ottowa"] = City{"Canada"}    m.Data["London"] = City{"GB"}    m.Data["malafya"] = City{"malafya"}    go m.Round()    for i := 0; i < 4; i++ {        go func() {            time.Sleep(2 * time.Second)            go m.Add("uz", City{"CityMakon"})            go m.Add("uzb", City{"CityMakon"})        }()    }    time.Sleep(5 * time.Second)    done <- struct{}{}}輸出:----- {Canada}----- {GB}----- {malafya}==================WARNING: DATA RACEWrite by goroutine 12:  runtime.mapassign1()      /usr/lib/golang/src/runtime/hashmap.go:411 +0x0  main.(*Map).Add()      /home/narkoz/elixir/round.go:37 +0xaaPrevious write by goroutine 6:  runtime.mapdelete()      /usr/lib/golang/src/runtime/hashmap.go:511 +0x0  main.(*Map).Round()      /home/narkoz/elixir/round.go:26 +0x3a9Goroutine 12 (running) created at:  main.main.func1()      /home/narkoz/elixir/round.go:54 +0x8cGoroutine 6 (running) created at:  main.main()      /home/narkoz/elixir/round.go:49 +0x2af==================----- {CityMakon}----- {CityMakon}Found 1 data race(s)exit status 66但是當我將映射的值類型更改為 int 或 string 時,沒有數據競爭。您推薦什么解決方案?
查看完整描述

1 回答

?
12345678_0001

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()

}


查看完整回答
反對 回復 2022-01-17
  • 1 回答
  • 0 關注
  • 259 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號