同步:负 WaitGroup 计数器

Der*_*ick 1 go slice waitgroup

谁能告诉我为什么会出现恐慌。这个demo的背景是验证切片并发写入的行为,但是当我运行demo时,偶尔会出现panic(并非总是如此)。所以为什么?

代码:

func main() {
    for i := 0; i < 10000; i++ {
                // when capacity > 2, panic disappear
        b := make([]int, 2, 2) 
        b[0], b[1] = 0, 1

        wg := sync.WaitGroup{}
        wg.Add(1)
        go func() {
            b = append(b, 3)
            wg.Done()
        }()
        wg.Add(1)
        go func() {
            b = append(b, 4)
            wg.Done()
        }()
        wg.Wait()
    }

}
Run Code Online (Sandbox Code Playgroud)

错误:

panic: sync: negative WaitGroup counter

goroutine 12821 [running]:
sync.(*WaitGroup).Add(0x0?, 0xc0000f4ba0?)
        /usr/local/go/src/sync/waitgroup.go:83 +0xda
sync.(*WaitGroup).Done(...)
        /usr/local/go/src/sync/waitgroup.go:108
main.main.func1()
        /Users/liushi/Projects/go/golang-demo/main.go:54 +0x97
created by main.main
        /Users/liushi/Projects/go/golang-demo/main.go:48 +0x11f

Process finished with the exit code 2

Run Code Online (Sandbox Code Playgroud)

当b的容量大于2时,panic就消失了。

Mar*_*ari 5

仅供参考:b是一个切片。切片有固定大小的数组支持它们。在你的例子中,b有两个元素并且它已经满了。因此,当你尝试这样做时append,Go 在追加之前必须做更多的工作,它必须将所有元素复制到新的后备数组中。如果将初始容量更改为3,则第一次调用append将很快执行。

您的代码的问题在于b变量上存在数据争用。如果您运行的话,这很容易验证。go test -race .要解决此问题,您可以使用互斥体来控制对b.

现在,我不知道为什么它会出现恐慌wg.Add(1),但由于您当前正在破坏内存,因此首先修复它,然后看看您是否会出现恐慌。我认为你不应该得到任何因为这WaitGroup部分对我来说看起来不错。