简体   繁体   中英

Go race condition when closing a Go channel

The following Go code example has a Race condition between the line c <- byte(0) and close(c) . It is signaled when the code is run with 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)
}

How can I avoid this race condition ?

Edit: based on Icza suggestion in his comments, here is the solution:

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)
}

This won't have a race condition and will be clean. It's a stupid simple example. I was told the select adds an overhead, but I didn't look into it because it isn't relevant in my use case.

Normally the goroutine that sends values on a channel is responsible to close it. Closing a channel is basically a signal that no more values will (can) be sent on it.

You are not doing this: your new goroutine is the one sending values on it, and your other goroutine is the one closing it.

To get rid of the race condition, simply use the channels as they were intended to: move the close(c) call to the goroutine that sends values on it, eg:

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)
}

Try it on the Go Playground .

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