Golang并发写入变量-为什么此代码有效?

时间:2019-05-23 11:19:54

标签: go concurrency locking mutex shared-memory

我正在学习Golang中与并发相关的问题。我写了一些代码:

package main

import (
    "fmt"
    "time"
)

func incr(num *int) {
    *num = *num + 1

}

func main() {
    var a = 0

    for i := 0; i < 50; i++ {
        go incr(&a)
    }

    incr(&a)

    time.Sleep(1 * time.Second)
    fmt.Println(a)
}

此代码的结果是:51

在这段代码中,我声明了a变量,并在50个正在运行的goroutine中增加了该变量。我已阅读并无法理解该代码的内容应该失败,因为多个goroutine正在写入同一内​​存地址。在这种情况下,我应该添加sync.Mutex锁以解决该问题。

操场上有可用的代码:https://play.golang.org/p/Tba9pfpxaHY

您能解释一下该程序中真正发生了什么吗?

1 个答案:

答案 0 :(得分:6)

猜猜是什么?我运行了您的应用程序,并得到了不同的输出:有时49,有时48,有时50(有时51)。

如果您在启用了竞赛检测器(go run -race play.go)的情况下运行您的应用,则它会告诉您数据竞赛:

==================
WARNING: DATA RACE
Read at 0x00c00009a010 by goroutine 7:
  main.incr()
      /home/icza/gows/src/play/play.go:9 +0x3a

Previous write at 0x00c00009a010 by goroutine 6:
  main.incr()
      /home/icza/gows/src/play/play.go:9 +0x50

Goroutine 7 (running) created at:
  main.main()
      /home/icza/gows/src/play/play.go:17 +0x83

Goroutine 6 (finished) created at:
  main.main()
      /home/icza/gows/src/play/play.go:17 +0x83
==================

发生数据争夺时,您的应用行为为未定义。 “有时似乎工作”也符合“未定义”的行为,但是未定义也意味着它也可以做其他任何事情。

查看相关问题:

Assign a map to another map is safety in golang?

Is it safe to read a function pointer concurrently without a lock?

golang struct concurrent read and write without Lock is also running ok?