普通网友 2018-08-04 06:59
浏览 3
已采纳

比赛条件改变

《Go in action》's sample about race conditions:

var (
    counter int
    wg sync.WaitGroup
)

func main() {
    wg.Add(2)
    go incCounter(1)
    go incCounter(2)

    wg.Wait()
    fmt.Println("Final Counter:", counter)
}

func incCounter(id int) {
    defer wg.Done()

    for count := 0; count < 2; count++ {
        value := counter
        //1 fmt.Println("value=",value)
        runtime.Gosched()

        value++

        counter = value
        //2 fmt.Println("counter=",counter)
    }
}

it is said Final Counter should be 2 in the end,here is explain: "Each goroutine overwrites the work of the other. This happens when the goroutine swap is taking place. Each goroutine makes its own copy of the counter variable and then is swapped out for the other goroutine. When the goroutine is given time to execute again, the value of the counter variable has changed, but the goroutine doesn’t update its copy. Instead it continues to increment the copy it has and set the value back to the counter variable, replacing the work the other goroutine performed."

I guess it's environment reason,my machine output 4 with go 1.10.3+win10. I want to know what the go changed since the book released? And if I uncomment mark 1 Final Counter prints 2 or random if I uncomment mark 2. why?

  • 写回答

1条回答 默认 最新

  • duanpa1980 2018-08-04 07:18
    关注

    The book is wrong. The essential point about a data race is the result is undefined.

    For example, Final Counter could be any value.

    package main
    
    import (
        "fmt"
        "runtime"
        "sync"
    )
    
    var (
        counter int
        wg      sync.WaitGroup
    )
    
    func main() {
        wg.Add(2)
        go incCounter(1)
        go incCounter(2)
    
        wg.Wait()
        fmt.Println("Final Counter:", counter)
    }
    
    func incCounter(id int) {
        defer wg.Done()
    
        for count := 0; count < 2; count++ {
            value := counter
            //1 fmt.Println("value=",value)
            runtime.Gosched()
    
            value++
    
            counter = value
            //2 fmt.Println("counter=",counter)
        }
    }
    

    Output:

    $ go version
    go version devel +65fa2b615b Fri Aug 3 23:35:53 2018 +0000 linux/amd64
    $ go run racer.go
    Final Counter: 4
    $ go run racer.go
    Final Counter: 2
    $ go run racer.go
    Final Counter: 2
    $ go run racer.go
    Final Counter: 2
    $ go run racer.go
    Final Counter: 2
    $ go run racer.go
    Final Counter: 4
    $ go run racer.go
    Final Counter: 2
    $ go run racer.go
    Final Counter: 4
    $ go run -race racer.go
    ==================
    WARNING: DATA RACE
    Read at 0x0000005e4600 by goroutine 7:
      main.incCounter()
          /home/peter/gopath/src/racer.go:27 +0x6f
    
    Previous write at 0x0000005e4600 by goroutine 6:
      main.incCounter()
          /home/peter/gopath/src/racer.go:33 +0x90
    
    Goroutine 7 (running) created at:
      main.main()
          /home/peter/gopath/src/racer.go:17 +0x89
    
    Goroutine 6 (finished) created at:
      main.main()
          /home/peter/gopath/src/racer.go:16 +0x68
    ==================
    Final Counter: 4
    Found 1 data race(s)
    exit status 66
    $
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分