无锁并发访问变量

Concurrent access to variable without lock

我被一个问题打扰了,

should we add lock if only one thread write variable, and other thread just read variable?

所以我写了这样的代码来测试一下

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

var lock sync.RWMutex
var i = 0

func main() {
    runtime.GOMAXPROCS(2)
    go func() {
        for {
            fmt.Println("i am here", i)
            time.Sleep(time.Second)
        }
    }()
    for {
        i += 1
    }
}

结果是保持打印 i am here 0 即使在第二秒之后。我对内存屏障或 cpu 缓存略知一二。但是怎么会缓存这么久呢?我想过几次后,它应该读取我已经更改过的变量。

请哪位高手go或电脑系统帮忙解答一下好吗?


Update:我知道像这样更新变量是错误的方法,我想知道为什么它在 cpu/memory 视图中未定义。

should we add lock if only one thread write variable, and other thread just read variable?

是的。总是。不争论了。

您的测试代码无法证明或反驳任何内容,因为它的行为是未定义的。

你有一场数据竞赛。因此,结果未定义。

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

var lock sync.RWMutex
var i = 0

func main() {
    runtime.GOMAXPROCS(2)
    go func() {
        for {
            fmt.Println("i am here", i)
            time.Sleep(time.Second)
        }
    }()
    for {
        i += 1
    }
}

输出:

$ go run -race racer.go
==================
WARNING: DATA RACE
Read at 0x0000005e3600 by goroutine 6:
  main.main.func1()
      /home/peter/gopath/src/racer.go:17 +0x63

Previous write at 0x0000005e3600 by main goroutine:
  main.main()
      /home/peter/gopath/src/racer.go:22 +0x7b

Goroutine 6 (running) created at:
  main.main()
      /home/peter/gopath/src/racer.go:15 +0x4f
==================
i am here 3622
i am here 43165250
i am here 86147697
^Csignal: interrupt
$

参考文献:

Data Race Detector

Benign Data Races: What Could Possibly Go Wrong?

最后,我找到了这个答案,我知道在数据竞争中你会得到一个未定义的行为,但我想知道为什么它目前的行为是这样的。

这个 snap 代码是因为编译器只是删除了 Add 函数,它从不添加。

所以我们有教训,如果你写一个未定义的行为,你可能会得到一个月亮 - -

编译器会将你的代码视为垃圾,它没有任何价值。