Go语言 sync:WaitGroup在上一个Wait返回之前被重用

3zwjbxry  于 2023-08-01  发布在  Go
关注(0)|答案(1)|浏览(82)

这段代码在许多goroutine中并发运行,下面的代码是从生产环境代码中提取的关键和相关部分:

func check() {

    .......check condition......

    //skipEnsure and skipNative will not both false here
    var wg sync.WaitGroup
    if !skipEnsure {
        wg.Add(1)
        go func(wg *sync.WaitGroup) {
            defer wg.Done()
            dosomething1()
        }(&wg)
    }
    if !skipNative {
        wg.Add(1)
        go func(wg *sync.WaitGroup) {
            defer wg.Done()
            dosomething2()
        }(&wg)
    }
    wg.Wait() //panic here
}

func worker() {
    ......

    go check()
}

func main() {
    for i:=0;i<32;i++ {
        go worker()
    }
    ch := make(chan any, 0)
    <-ch
}

字符串
当WaitGroup是一个全局变量时,我可以重现这个问题,但不能在提供的代码中重现。在生产环境中运行一段时间后,它可能会导致死机。

wqsoz72f

wqsoz72f1#

如果我理解正确的话,代码看起来像这样:
WaitGroup不是为这种用途设计的。何时调用wg.add和wg.wait并不明显。如果您尝试使用数据竞争检测器运行它,您可以看到如下内容:

==================
WARNING: DATA RACE
Write at 0x0000011707e8 by goroutine 6:
  runtime.racewrite()
      <autogenerated>:1 +0x24
  main.work()
      /1.go:23 +0x1b2

Previous read at 0x0000011707e8 by goroutine 7:
  runtime.raceread()
      <autogenerated>:1 +0x24
  main.work()
      /1.go:11 +0x35

Goroutine 6 (running) created at:
  main.main()
      /1.go:28 +0x32

Goroutine 7 (running) created at:
  main.main()
      /1.go:28 +0x32
==================
Found 1 data race(s)

字符串
你可以为每个goroutine使用自己的WaitGroup(如你的例子)。我想不出有什么理由反对它。例如,下面的代码可以很好地工作,没有任何数据竞争:

package main

import (
    "sync"
    "time"
)

func work() {
    var wg sync.WaitGroup
    wg.Add(1)
    go func(wg *sync.WaitGroup) {
        defer wg.Done()
        time.Sleep(1 * time.Millisecond)
        println("one done")
    }(&wg)
    wg.Add(1)
    go func(wg *sync.WaitGroup) {
        defer wg.Done()
        time.Sleep(2 * time.Millisecond)
        println("two done")
    }(&wg)
    wg.Wait() //panic here
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            work()
            wg.Done()
        }()
    }
    wg.Wait()
    println("done")
}

相关问题