Home > Net >  golang race with channels and return in a function
golang race with channels and return in a function

Time:01-10

I have the following 3 files: go.mod

module example

go 1.19

main.go

package main

import "fmt"

func number(out chan int) bool {
    defer close(out)

    for i := 0; i < 5; i   {
        out <- i
    }

    return true
}

func main() {
    in := make(chan int)
    var ret bool

    go func() {
        ret = number(in)
    }()

    for i := range in {
        fmt.Println(i)
    }

    if !ret {
        fmt.Println(ret)
    }
}

and main_test.go

package main

import "testing"

func TestMain(t *testing.T) {
    t.Run("test", func(t *testing.T) {
        main()
    })
}

I seem to hit a race condition with the ret variable. Why is this an issue, shouldn't range in be blocking till the channel is closed in the number function. And hence ret will have the returned status, before it is read? Also, is there a way to resolve this without using the sync package or another channel?

When I run the test with -race option, I get the following error $ go test -race

0
1
2
3
4
==================
WARNING: DATA RACE
Read at 0x00c00002023f by goroutine 8:
  example.main()
      /example/main.go:27  0x174
  example.TestMain.func1()
      /example/main_test.go:13  0x24
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1446  0x216
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1493  0x47

Previous write at 0x00c00002023f by goroutine 9:
  example.main.func1()
      /example/main.go:20  0x47

Goroutine 8 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1493  0x75d
  example.TestMain()
      /example/main_test.go:12  0x64
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1446  0x216
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1493  0x47

Goroutine 9 (finished) created at:
  example.main()
      /example/main.go:19  0xfe
  example.TestMain.func1()
      /example/main_test.go:13  0x24
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1446  0x216
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1493  0x47
==================
--- FAIL: TestMain (0.00s)
    --- FAIL: TestMain/test (0.00s)
        testing.go:1319: race detected during execution of test
    testing.go:1319: race detected during execution of test
FAIL
exit status 1
FAIL    example 1.555s

CodePudding user response:

When ret is read in main, it is guaranteed that the channel is closed, but it is not guaranteed that the assignment to ret is completed. Thus, it is a race.

  • Related