Search code examples
concurrencygorace-conditiongoroutine

Golang - Why does this race condition occur?


package main
import "fmt"

var quit chan int
var glo int

func test() {
    fmt.Println(glo)
}

func main() {
    glo = 0
    n := 10000
    quit = make(chan int, n)
    go test()
    for {
        quit <- 1
        glo++
    }
}

Situation:

The above program outputs 10000. But when I assign a bigger number to n (e.g. n := 1000000), the output will be a random number less than n.

I haven't called runtime.GOMAXPROCS(), so these two goroutines can't run in parallel. Executing go run -race to detect race conditions, ends up without any warnings.

Question:

Why does this race condition occur?


Solution

  • As there is no synchronisation between the main and test goroutines, you don't know at what point the fmt.Println call in test will happen.

    When running with GOMAXPROCS = 1, the answer will essentially depend on when the scheduler decides to stop executing main and switch to test. The send operation within the loop is one point where the scheduler can switch over to another goroutine, so with enough iterations of the loop you'd expect test to get a chance to execute at some point. It isn't necessarily going to switch at the same iteration every run leading to the variation in results.

    As for catching this with the race detector, it successfully catches the problem for me:

    $ go run -race test.go
    ==================
    WARNING: DATA RACE
    Read by goroutine 5:
      main.test()
          /../test.go:8 +0x6e
    
    Previous write by main goroutine:
      main.main()
          /.../test.go:18 +0xfe
    
    Goroutine 5 (running) created at:
      main.main()
          /.../test.go:15 +0x8f
    ==================
    ...