是否可以使用 select 从多个 goroutine 中安全地关闭一次通道?

Jul*_*ska 0 concurrency channel go goroutine

我的解决方案如下,但是以下代码中是否存在竞争条件(它会出现恐慌)吗?

c := make(chan struct{})

for i := 0; i < 1000000; i++ {
    go func() {
        select {
        case <-c:
        default:
            close(c)
        }
    }()
}
Run Code Online (Sandbox Code Playgroud)

我认为是的,但是 go test -race 没有检测到它,并且根据经验,我无法让它恐慌。

icz*_*cza 5

您在没有同步的情况下启动多个 goroutine。所以它们同时运行。可能会发生其中两个<-c并行评估的情况,因为这是一个阻塞操作,因此两者都会选择这种default情况。此时,这两个 goroutine 都会尝试关闭通道,只有其中一个会成功,另一个会恐慌:你无法关闭已关闭的通道。

这不是竞争条件,因为您不会同时读取/修改变量,但尝试关闭关闭的通道会导致运行时恐慌(因此竞争检测器永远不会捕获此情况)。

当一个通道上有多个 Goroutine 发送数据时,等待所有的完成,然后在单个 Goroutine 中关闭该通道。不要尝试从多个 goroutine 关闭通道。