关闭 Go channel 时的​​ Go 竞争条件

标签 go concurrency race-condition channel goroutine

以下 Go 代码示例在行 c <- byte(0) 之间有一个竞争条件和 close(c) .当使用 go test -race 运行代码时会发出信号.

func TestRace(t *testing.T) {
    var c = make(chan byte, 20)
    go func() {
        defer func() {
            if r := recover(); r == nil {
                t.Error("expected panic error")
            }
        }()
        for i := 0; i < 25; i++ {
            c <- byte(0)
        }
        t.Error("expected a panic")
    }()
    close(c)
}

如何避免这种竞争情况?

编辑:根据 Icza 在他的评论中的建议,这里是解决方案:

func TestRace(t *testing.T) {
    var c = make(chan byte, 20)
    var done = make(chan struct{})
    go func() {
        for i := 0; i < 25; i++ {
            select{
            case c <- byte(0):
            case <-done:
                close(c)
                return
        }
    }()
    close(done)
}

这不会有竞争条件,而且是干净的。这是一个愚蠢的简单例子。有人告诉我 select 会增加开销,但我没有研究它,因为它与我的用例无关。

最佳答案

通常,在 channel 上发送值的 goroutine 负责关闭它。关闭 channel 基本上是一个信号,表示将(不能)在其上发送更多值。

您没有这样做:您的新 goroutine 是在其上发送值的 goroutine,而您的另一个 goroutine 是关闭它的 goroutine。

要摆脱竞争条件,只需按预期使用 channel :将 close(c) 调用移动到在其上发送值的 goroutine,例如:

go func() {
    defer func() {
        if r := recover(); r == nil {
            fmt.Println("expected panic error")
        }
    }()
    for i := 0; i < 25; i++ {
        c <- byte(0)
    }
    close(c)
    fmt.Println("expected a panic")
}()
for x := range c {
    fmt.Println("Received:", x)
}

Go Playground 上试试.

关于关闭 Go channel 时的​​ Go 竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47714470/

相关文章:

json - 使用更改的 JSON 属性解码

java - Java多线程和文件

java迭代器并发修改即使有预防措施

javascript - 使用 Ajax 的 Angular.js 中的 2 个 Controller 和本地存储值之间存在竞争条件问题

C# 控制台应用程序任务的线程问题

linux - 跟踪 Linux 上的文件描述符事件

go - Bazel 没有将 BUILD 文件添加到外部依赖项

html - 如何用xpath解析html字符串

go - 代理网关发回HTTP响应

java - 如何使用 Thread.sleep() 和 setBackground() 在 Swing 中创建闪光效果?