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.