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

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

觀察循環內的無效值

觀察循環內的無效值

Go
拉丁的傳說 2023-07-17 14:19:41
我偶然發現了一個有缺陷的 Golang 代碼,該代碼試圖使用互斥體來防止對 Goroutine 中打印的變量進行更改:    runtime.GOMAXPROCS(1)    mutex := new(sync.Mutex)    for i := 0; i < 10; i++ {        for j := 0; j < 10; j++ {            mutex.Lock()            go func() {                fmt.Println(i, j, i + j);                mutex.Unlock()            }()        }    }我很清楚,互斥體不會直接鎖定,而是在下一次迭代中,當值已經增加時鎖定。不清楚的是,根據輸出,為什么 j 變量達到 10:...0 7 70 8 80 9 91 10 11   <--- isn't supposed to be here...1 9 102 10 12...我嘗試調試代碼,并j = 10在 i 的外循環增加其值時打印??雌饋砗孟裢獠垦h正在釋放線程,允許 goroutine 執行并看到無效值 10。有人可以澄清這種行為嗎?
查看完整描述

3 回答

?
郎朗坤

TA貢獻1921條經驗 獲得超9個贊

你有數據競爭。結果未定義。


$ go run -race racer.go

==================

WARNING: DATA RACE

Read at 0x00c000016110 by goroutine 7:

? main.main.func1()

? ? ? /home/peter/gopath/racer.go:17 +0x7f


Previous write at 0x00c000016110 by main goroutine:

? main.main()

? ? ? /home/peter/gopath/racer.go:14 +0xf1


Goroutine 7 (running) created at:

? main.main()

? ? ? /home/peter/gopath/racer.go:16 +0xcd

==================

0 1 1

0 2 2

0 3 3

0 4 4

0 5 5

0 6 6

0 7 7

0 8 8

0 9 9

==================

WARNING: DATA RACE

Read at 0x00c000016108 by goroutine 16:

? main.main.func1()

? ? ? /home/peter/gopath/racer.go:17 +0x50


Previous write at 0x00c000016108 by main goroutine:

? main.main()

? ? ? /home/peter/gopath/racer.go:13 +0x140


Goroutine 16 (running) created at:

? main.main()

? ? ? /home/peter/gopath/racer.go:16 +0xcd

==================

1 10 11

1 1 2

1 2 3

1 3 4

1 4 5

1 5 6

1 6 7

1 7 8

1 8 9

1 9 10

2 10 12

2 1 3

2 2 4

2 3 5

2 4 6

2 5 7

2 6 8

2 7 9

2 8 10

2 9 11

3 10 13

3 1 4

3 2 5

3 3 6

3 4 7

3 5 8

3 6 9

3 7 10

3 8 11

3 9 12

4 10 14

4 1 5

4 2 6

4 3 7

4 4 8

4 5 9

4 6 10

4 7 11

4 8 12

4 9 13

5 10 15

5 1 6

5 2 7

5 3 8

5 4 9

5 5 10

5 6 11

5 7 12

5 8 13

5 9 14

6 10 16

6 1 7

6 2 8

6 3 9

6 4 10

6 5 11

6 6 12

6 7 13

6 8 14

6 9 15

7 10 17

7 1 8

7 2 9

7 3 10

7 4 11

7 5 12

7 6 13

7 7 14

7 8 15

7 9 16

8 10 18

8 1 9

8 2 10

8 3 11

8 4 12

8 5 13

8 6 14

8 7 15

8 8 16

8 9 17

9 10 19

9 1 10

9 2 11

9 3 12

9 4 13

9 5 14

9 6 15

9 7 16

9 8 17

9 9 18

Found 2 data race(s)

exit status 66

$?

racer.go:


package main


import (

? ? "fmt"

? ? "runtime"

? ? "sync"

)


func main() {

? ? runtime.GOMAXPROCS(1)


? ? mutex := new(sync.Mutex)

? ? for i := 0; i < 10; i++ {

? ? ? ? for j := 0; j < 10; j++ {

? ? ? ? ? ? mutex.Lock()

? ? ? ? ? ? go func() {

? ? ? ? ? ? ? ? fmt.Println(i, j, i+j)

? ? ? ? ? ? ? ? mutex.Unlock()

? ? ? ? ? ? }()

? ? ? ? }

? ? }

}


查看完整回答
反對 回復 2023-07-17
?
子衿沉夜

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

您存在數據競爭,因此結果未定義。運行它并-race選擇查看。

當您mutex.Lock()首先在循環體內調用時,不會阻塞。然后,您啟動一個 goroutine 來讀取ij,并且主 goroutine 繼續進行內循環的下一次迭代,并遞增j。然后再次調用lock,這將阻塞直到前一個goroutine完成。

但是您已經對j.


查看完整回答
反對 回復 2023-07-17
?
繁星淼淼

TA貢獻1775條經驗 獲得超11個贊

讓我來回答為什么打印時可以得到不可能的j10 。


因為當你在循環中使用 goroutine 時,fmt.Println(i, j, i+j)race with i++/j++,你無法確定打印時到底是什么值,而如果j增加到界限,有可能打印出 10。


如果你想阻止這場比賽,你可以將i,j作為參數值傳遞,例如


    runtime.GOMAXPROCS(1)


    for i := 0; i < 10; i++ {

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

            go func(a, b, c int) {

                fmt.Println(a, b, c);

            }(i, j, i+j)

        }

    }

希望這可以幫助。


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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