golang race with channels and return in a function

huangapple go评论77阅读模式
英文:

golang race with channels and return in a function

问题

我有以下3个文件:
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)
	}
}

main_test.go

package main

import "testing"

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

我似乎遇到了ret变量的竞态条件。为什么会出现这个问题?range in不应该在number函数中的通道关闭之前一直阻塞吗?因此,在读取ret之前,它将具有返回的状态。此外,是否有一种方法可以解决这个问题,而不使用sync包或另一个通道?

当我使用-race选项运行测试时,我得到以下错误$ 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
英文:

I have the following 3 files:
go.mod

module example

go 1.19

main.go

package main

import &quot;fmt&quot;

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

	for i := 0; i &lt; 5; i++ {
		out &lt;- 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 &quot;testing&quot;

func TestMain(t *testing.T) {
	t.Run(&quot;test&quot;, 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

答案1

得分: 2

当在main函数中读取ret时,可以确保通道已关闭,但不能确保对ret的赋值已完成。因此,这是一个竞争条件。

英文:

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.

huangapple
  • 本文由 发表于 2023年1月10日 00:25:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/75060185.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定