为什么与goroutine的竞争条件不会在一段时间内发生?

时间:2017-07-23 14:47:43

标签: go race-condition goroutine

我正在阅读行动。这个例子来自第6章/ listing09.go。

// This sample program demonstrates how to create race
// conditions in our programs. We don't want to do this.
package main

import (
  "fmt"
  "runtime"
  "sync"
)

var (
  // counter is a variable incremented by all goroutines.
  counter int

  // wg is used to wait for the program to finish.
  wg sync.WaitGroup
)

// main is the entry point for all Go programs.
func main() {
  // Add a count of two, one for each goroutine.
  wg.Add(2)

  // Create two goroutines.
  go incCounter(1)
  go incCounter(2)

  // Wait for the goroutines to finish.
  wg.Wait()
  fmt.Println("Final Counter:", counter)
 }

 // incCounter increments the package level counter variable.
 func incCounter(id int) {
    // Schedule the call to Done to tell main we are done.
    defer wg.Done()

    for count := 0; count < 2; count++ {
      // Capture the value of Counter.
      value := counter

      // Yield the thread and be placed back in queue.
      runtime.Gosched()

      // Increment our local value of Counter.
      value++

      // Store the value back into Counter.
      counter = value
  }
}

如果你在play.golang.org中运行此代码,它将是2,与本书相同。 但我的mac打印4大部分时间,有些时间2,有时甚至3。

$ go run listing09.go 
Final Counter: 2
$ go run listing09.go 
Final Counter: 4
$ go run listing09.go 
Final Counter: 4
$ go run listing09.go 
Final Counter: 4
$ go run listing09.go 
Final Counter: 4
$ go run listing09.go 
Final Counter: 2
$ go run listing09.go 
Final Counter: 4
$ go run listing09.go 
Final Counter: 2
$ go run listing09.go 
Final Counter: 3

的sysinfo     去版本go1.8.1 darwin / amd64     macOS sierra     Macbook Pro

书中的解释(p140)

  

每个goroutine都会覆盖另一个人的工作。发生goroutine交换时会发生这种情况。每个goroutine都会创建自己的计数器变量副本,然后换出另一个goroutine。当goroutine再次执行时,计数器变量的值已更改,但goroutine不会更新其副本。相反,它继续增加它的副本并将值设置回计数器变量,替换另一个goroutine执行的工作。

根据此说明,此代码应始终打印2。

  1. 为什么我得到4和3?是因为竞争条件没有发生?

  2. 为什么去游乐场总会得到2?

  3. 更新

    设置runtime.GOMAXPROCS(1)后,它开始打印2,没有4,有些3。 我想play.golang.org配置为有一个逻辑处理器。

    正确的结果4没有竞争条件。一个逻辑处理器意味着一个线程GO默认具有与物理核相同的逻辑处理器。所以, 为什么一个线程(一个逻辑处理器)导致竞争条件,而多个线程打印正确答案?

    我们可以说这本书的解释是错误的,因为我们也得到了3和4吗? 怎么得到3? 4是正确的。

1 个答案:

答案 0 :(得分:2)

根据定义,种族条件是不确定的。这意味着虽然大多数时候你可能会得到一个特定的答案,但并不总是如此。

通过在多个核心上运行racy代码,您可以大大增加可能性,从而获得更广泛的结果选择。

有关竞争条件的详情,请参阅this postthis Wikipedia article