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

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

為什么 Go 在這段代碼中的 Printf 上檢測到競爭條件

為什么 Go 在這段代碼中的 Printf 上檢測到競爭條件

Go
慕仙森 2023-07-31 16:43:24
我編寫了一些簡單的 Go 代碼來理解競爭條件,如下所示:package mainimport (    "fmt"    "sync")type outer struct {    sync.Mutex    num int    foo string}func (outer *outer) modify(wg *sync.WaitGroup) {    outer.Lock()    defer outer.Unlock()    outer.num = outer.num + 1    wg.Done()}func main() {    outer := outer{        num: 2,        foo: "hi",    }    var w sync.WaitGroup    for j := 0; j < 5000; j++ {        w.Add(1)        go outer.modify(&w)    }    w.Wait()    fmt.Printf("Final is %+v", outer)}當我在上面運行時,打印的答案始終是正確的,即 num 始終是 5002。如果沒有鎖,由于 forloop 中創建的 goroutine 之間的競爭,答案將無法預測。但是,當我使用 -race 運行此命令時,會檢測到以下競爭條件:go run -race random.go==================WARNING: DATA RACERead at 0x00c00000c060 by main goroutine:  main.main()      random.go:32 +0x15dPrevious write at 0x00c00000c060 by goroutine 22:  sync/atomic.AddInt32()      /usr/local/go/src/runtime/race_amd64.s:269 +0xb  sync.(*Mutex).Unlock()      /usr/local/go/src/sync/mutex.go:182 +0x54  main.(*outer).modify()      random.go:19 +0xb7Goroutine 22 (finished) created at:  main.main()      random.go:29 +0x126==================Final is {Mutex:{state:0 sema:0} num:5002 foo:hi}Found 1 data race(s)exit status 66IE。它正在檢測最終的 Printf 和在其之前創建的一個隨機 go 例程之間的競爭。由于我使用等待來同步,所以當我們到達 Printf 時,所有 go 例程都已完成。比賽被報道的原因是什么?我還需要鎖定打印結構嗎?
查看完整描述

2 回答

?
holdtom

TA貢獻1805條經驗 獲得超10個贊

使用不當sync.WaitGroup是導致您出現競爭狀況的原因。其中任何一個都應該正常工作:


func (outer *outer) modify(wg *sync.WaitGroup) {

    outer.Lock()

    outer.num = outer.num + 1

    outer.Unlock()

    wg.Done()

}

func (outer *outer) modify(wg *sync.WaitGroup) {

    outer.Lock()

    defer wg.Done()

    defer outer.Unlock()

    outer.num = outer.num + 1

}

wg.Done()應該在解鎖互斥鎖之后調用(延遲調用以 LIFO 方式進行),因為之前調用它會導致調用Printf()與最后一個outer.Unlock()調用競爭以訪問outer.


查看完整回答
反對 回復 2023-07-31
?
萬千封印

TA貢獻1891條經驗 獲得超3個贊

package main


import (

    "fmt"

    "sync"

)


type outer struct {

    *sync.Mutex

    num int

    foo string

}


func (outer *outer) modify(wg *sync.WaitGroup) {

    outer.Lock()

    defer outer.Unlock()

    outer.num++

    wg.Done()

}


func main() {

    outer := outer{

        Mutex: &sync.Mutex{},

        num:   2,

        foo:   "hi",

    }

    w := &sync.WaitGroup{}

    for j := 0; j < 5000; j++ {

        w.Add(1)

        go outer.modify(w)

    }

    w.Wait()

    fmt.Printf("Final is %+v", outer)

}

將sync.Mutex 更改為指針。


我認為這是由于sync.Mutex 在您的版本中很有價值


查看完整回答
反對 回復 2023-07-31
  • 2 回答
  • 0 關注
  • 143 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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