3 回答

TA貢獻1802條經(jīng)驗 獲得超10個贊
您有競爭條件,請使用 -race 標志運行您的程序
go run -race main.go
==================
WARNING: DATA RACE
Read at 0x0000005e9600 by main goroutine:
? main.main()
? ? ? /home/jack/Project/GoProject/src/gitlab.com/hooshyar/GoNetworkLab/StackOVerflow/race/main.go:17 +0x6c
Previous write at 0x0000005e9600 by goroutine 6:
? main.main.func1()
? ? ? /home/jack/Project/GoProject/src/gitlab.com/hooshyar/GoNetworkLab/StackOVerflow/race/main.go:13 +0x56
Goroutine 6 (running) created at:
? main.main()
? ? ? /home/jack/Project/GoProject/src/gitlab.com/hooshyar/GoNetworkLab/StackOVerflow/race/main.go:11 +0x46
==================
result=119657339
Found 1 data race(s)
exit status 66
什么是解決方案?
有一些解決方案,一個解決方案是使用互斥體:
var a = 0
func main() {
? ? var mu sync.Mutex
? ? go func() {
? ? ? ? for {
? ? ? ? ? ? mu.Lock()
? ? ? ? ? ? a = a + 1
? ? ? ? ? ? mu.Unlock()
? ? ? ? }
? ? }()
? ? time.Sleep(3*time.Second)
? ? mu.Lock()
? ? fmt.Printf("result=%d\n", a)
? ? mu.Unlock()
}
在任何讀寫鎖定互斥體然后解鎖它之前,現(xiàn)在您沒有任何競爭,并且結(jié)果將在最后為 big int 。

TA貢獻1848條經(jīng)驗 獲得超6個贊
存在數(shù)據(jù)競爭,但如果將此行為與使用 pthreads 用 C 編寫的程序進行比較,則會丟失一些重要數(shù)據(jù)。您的問題不僅僅是時間問題,還與語言定義有關(guān)。由于并發(fā)原語已融入到語言本身中,因此 Go 語言內(nèi)存模型 (?https://golang.org/ref/mem?) 準確地描述了一個 Goroutine 何時以及如何更改——將 Goroutine 視為“超輕量級用戶空間”線程”,你不會離得太遠——保證對另一個 goroutine 中運行的代碼可見。
如果沒有任何同步操作,例如通道發(fā)送/接收或sync.Mutex 鎖定/解鎖,Go 內(nèi)存模型表示,您對該 goroutine 內(nèi)的“a”所做的任何更改都不必對主 goroutine可見。而且,由于編譯器知道這一點,因此可以自由地優(yōu)化 for 循環(huán)中的幾乎所有內(nèi)容。或不。
這與 C 中的局部 int 變量設(shè)置為 1 時的情況類似,并且可能有一個 while 循環(huán)在循環(huán)中讀取該變量,等待 ISR 將其設(shè)置為 0,但隨后編譯器變得太聰明并決定優(yōu)化為零的測試,因為它認為你的變量在循環(huán)內(nèi)永遠不會改變,而你真的只是想要一個無限循環(huán),所以你必須聲明變量來volatile
修復(fù)“錯誤”。
如果您打算使用 Go(我目前最喜歡的語言,F(xiàn)WIW)工作,請花時間閱讀并徹底理解上面鏈接的 Go 內(nèi)存模型,這將在未來真正得到回報。

TA貢獻1827條經(jīng)驗 獲得超9個贊
您的程序正在進入競爭狀態(tài)。go
可以檢測到此類場景。
嘗試運行您的程序,go run -race main.go
假設(shè)您的文件名為main.go
. 它將顯示競爭如何發(fā)生,嘗試在 Goroutine 內(nèi)寫入,并由主 Goroutine 同時讀取。它還會按照您的預(yù)期打印一個隨機 int 數(shù)字。
- 3 回答
- 0 關(guān)注
- 239 瀏覽
添加回答
舉報