简体   繁体   中英

golang race with channels and return in a function

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM