duanhao4909 2017-05-03 23:46
浏览 50
已采纳

甚至在golang中使用sync.Mutex时的比赛条件

Complete code is here: https://play.golang.org/p/ggUoxtcv5m go run -race main.go says there is a race condition there which I fail to explain. The program outputs correct final result, though.

The essence:

type SafeCounter struct {
    c int
    sync.Mutex
}

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

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

use *SafeCounter in incrementor:

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

The incrementor method is spawned twice in main:

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

So, as I said, go run -race main.go will always say there is a race cond found.

Also, the final result is always correct (at least I've run this program for a number of times and it always say final counter is 40, which is correct). BUT, the program prints incorrect values in the beginning so you can get something like:

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

so, printing out 1 is missing there.

Can somebody explain why there is a race condition there is my code?

  • 写回答

2条回答 默认 最新

  • doulingqiu4349 2017-05-04 00:21
    关注

    You have a number of race conditions, all pointed out specifically by the race detector:

        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 is between the read and the write of the counter value in incrementor

    • race #2 is between the concurrent writes to the counter value in incrementor

    • race #3 is between the read of the x.c field in fmt.Println, and the increment to x.c in the Add method.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看