繁体   English   中英

即使在golang中使用sync.Mutex也会出现竞争情况

[英]Race condition even when using sync.Mutex in golang

完整的代码在这里: 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将始终说有一个比赛cond发现。

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

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

所以,那里缺少打印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
  • 种族#1在incrementor读取和写入counter值之间

  • 第2场比赛是在incrementorcounter值的并发写入之间

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

读取和写入计数器指针的两行不受互斥锁保护,并且是从多个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
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM