dongsanhu4784 2018-07-11 14:15
浏览 65

从goroutine更改变量

I tried to write sample program with 2 goroutines to illustrate race condition. One print x, another increment x.

package main

import (
    "fmt"
    "time"
)

func main() {
    x := 0

    go func() {
        for {
            if x%2 == 0 {
                fmt.Println(x)
            }
        }
    }()

    go func() {
        for {
            x = x + 1
        }
    }()

    <-time.After(1 * time.Second)
    fmt.Println("final", x)
}

But incremental routine do nothing and finally in x stays zero. But if incremental routine add fmt.Println(x) it starts to increment x and program working as expected.

UPDATE #1:

Purpose of this simple example is only to illustrate data race issue. I know that reading a shared variable between two goroutines without synchronization is a bad idea. Please stop to point me out to that. My question is why incremental goroutine do nothing here? In my picture of the world is should steadily increment, but the issue should appear in the reading goroutine where result may be not determined, because when reading x is one, but when printing x may be other.

UPDATE #2:

I have another example:

package main

import (
    "time"
    "fmt"
)

func main() {
    x := 0

    go func() {
        last := x
        for {
            current := x
            if last != current {
                last = current
                fmt.Println(last)
            }
        }
    }()

    go func() {
        for {
            //<-time.After(1 * time.Second) // if uncomment this row program start do "something"
            x = x + 1
        }
    }()

    <-time.After(10 * time.Second)
    fmt.Println("final", x)
}

The example is pretty straightforward. One routine increment counter, other print if changed. This program has undefined behaviour only in the case when writing x = x+1 and read current := x it is not atomic operation and one thread start read the variable in the middle of writing in the other thread and reading operations will read corrupted value. But why in this case when uncomment sleep in incremental routine program starts to do something?

  • 写回答

2条回答 默认 最新

  • doter1995 2018-07-11 15:34
    关注

    You have data races: Go Data Race Detector. Therefore, your results are undefined.


    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        x := 0
    
        go func() {
            for {
                if x%2 == 0 {
                    //fmt.Println(x)
                }
            }
        }()
    
        go func() {
            for {
                x = x + 1
            }
        }()
    
        <-time.After(1 * time.Second)
        fmt.Println("final", x)
    }
    

    Output:

    $ go run -race racer.go > /dev/null
    ==================
    WARNING: DATA RACE
    Write at 0x00c000088010 by goroutine 7:
      main.main.func2()
          /home/peter/gopath/src/racer.go:21 +0x4e
    
    Previous read at 0x00c000088010 by goroutine 6:
      main.main.func1()
          /home/peter/gopath/src/racer.go:13 +0x38
    
    Goroutine 7 (running) created at:
      main.main()
          /home/peter/gopath/src/racer.go:19 +0x9c
    
    Goroutine 6 (running) created at:
      main.main()
          /home/peter/gopath/src/racer.go:11 +0x7a
    ==================
    Found 1 data race(s)
    exit status 66
    $ 
    

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        x := 0
    
        go func() {
            for {
                if x%2 == 0 {
                    fmt.Println(x)
                }
            }
        }()
    
        go func() {
            for {
                x = x + 1
            }
        }()
    
        <-time.After(1 * time.Second)
        fmt.Println("final", x)
    }
    

    Output:

    $ go run -race racer.go > /dev/null
    ==================
    WARNING: DATA RACE
    Read at 0x00c00008c010 by goroutine 6:
      main.main.func1()
          /home/peter/gopath/src/racer.go:13 +0x3c
    
    Previous write at 0x00c00008c010 by goroutine 7:
      main.main.func2()
          /home/peter/gopath/src/racer.go:21 +0x4e
    
    Goroutine 6 (running) created at:
      main.main()
          /home/peter/gopath/src/racer.go:11 +0x7a
    
    Goroutine 7 (running) created at:
      main.main()
          /home/peter/gopath/src/racer.go:19 +0x9c
    ==================
    ==================
    WARNING: DATA RACE
    Write at 0x00c00008c010 by goroutine 7:
      main.main.func2()
          /home/peter/gopath/src/racer.go:21 +0x4e
    
    Previous read at 0x00c00008c010 by goroutine 6:
      main.main.func1()
          /home/peter/gopath/src/racer.go:13 +0x3c
    
    Goroutine 7 (running) created at:
      main.main()
          /home/peter/gopath/src/racer.go:19 +0x9c
    
    Goroutine 6 (running) created at:
      main.main()
          /home/peter/gopath/src/racer.go:11 +0x7a
    ==================
    ^Csignal: interrupt
    $ 
    
    评论

报告相同问题?

悬赏问题

  • ¥17 pro*C预编译“闪回查询”报错SCN不能识别
  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥188 需要修改一个工具,懂得汇编的人来。