【问题标题】:Race condition even when using sync.Mutex in golang即使在 golang 中使用 sync.Mutex 也会出现竞争条件
【发布时间】:2017-10-01 23:24:06
【问题描述】:

完整代码在这里:https://play.golang.org/p/ggUoxtcv5m go run -race main.go 说那里存在竞争条件,我无法解释。 不过,程序会输出正确的最终结果。

本质:

type SafeCounter struct {
    c int
    sync.Mutex
}

func (c *SafeCounter) Add() {
    c.Lock()
    c.c++
    c.Unlock()
}

var counter *SafeCounter = &SafeCounter{} // global

在增量器中使用*SafeCounter:

func incrementor(s string) {
    for i := 0; i < 20; i++ {
        x := counter
        x.Add()
        counter = x
    }
}

incrementor 方法在 main 中产生了两次:

func main() {
    go incrementor()
    go incrementor()
    // some other non-really-related stuff like
    // using waitGroup is ommited here for problem showcase
}

所以,正如我所说,go run -race main.go 总是会说找到了比赛条件。

另外,最终结果总是正确的(至少我已经多次运行这个程序,它总是说最终计数器是 40,这是正确的)。 但是,程序在开始时会打印不正确的值,因此您可以得到类似的结果:

Incrementor1: 0 Counter: 2
Incrementor2: 0 Counter: 3
Incrementor2: 1 Counter: 4
// ang the rest is ok

所以,那里缺少打印出1。

有人可以解释为什么我的代码存在竞争条件吗?

【问题讨论】:

    标签: go mutex race-condition


    【解决方案1】:

    您有许多竞态条件,所有竞态检测器都特别指出:

        x := counter      // this reads the counter value without a lock
        fmt.Println(&x.c)
        x.Add()
        counter = x       // this writes the counter value without a lock
        time.Sleep(time.Duration(rand.Intn(3)) * time.Millisecond)
        fmt.Println(s, i, "Counter:", x.c) // this reads the c field without a lock
    
    • race #1 在incrementor 中counter 值的读取和写入之间

    • race #2 在incrementor 中counter 值的并发写入之间

    • race #3 介于读取fmt.Println 中的x.c 字段和Add 方法中的x.c 增量之间。

    【讨论】:

      【解决方案2】:

      读取和写入计数器指针的两行不受互斥体保护,由多个 goroutine 并发完成。

      func incrementor(s string) {
          for i := 0; i < 20; i++ {
              x := counter  // <-- this pointer read
              x.Add()
              counter = x   // <-- races with this pointer write
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-18
        • 1970-01-01
        • 2021-09-23
        • 2023-04-06
        相关资源
        最近更新 更多