go - 观察循环内的无效值

标签 go

我偶然发现了一个有问题的 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()
            }()
        }
    }

我很清楚 mutex 不会直接锁定,而是在下一次迭代时,当值已经递增时。不清楚的是为什么根据输出j变量达到10:

...
0 7 7
0 8 8
0 9 9
1 10 11   <--- isn't supposed to be here
...
1 9 10
2 10 12
...

我尝试调试代码,当 i 的外循环递增其值时打印了 j = 10。看起来好像外层循环正在释放线程以允许 goroutine 执行并看到无效值 10。有人可以澄清这种行为吗?

最佳答案

您有数据竞争。结果未定义。

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

Go: Data Race Detector

关于go - 观察循环内的无效值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57620363/

相关文章:

http - 在 golang 中关闭 keep alive

linux - 调试器在带有 "Go"插件的 IntelliJ IDEA 中不起作用

json - Golang 解码 map[string]float 其中 float 被编码为字符串

go - 在异常期间在 golang 中运行测试用例

javascript - 在将数据推送到模板时使链接可点击

go - 当没有定义 $GOPATH 时,如何查找安装了 'go get -u' 的 Go 包?

go - Golang-为什么总是ItoA在返回字符串时删除初始0

c - 如何将 uint8_t 数组从 C 发送到 GO

mongodb - 如何使用权重在 mgo 中定义 mongodb 文本索引

forms - 使用 http.NewRequest POST 数据失败