【问题标题】:sync.WaitGroup deadlock caused by pass by value?传值引起的sync.WaitGroup死锁?
【发布时间】:2018-07-28 04:41:31
【问题描述】:

有两种写repro的方法:

第一种方式,程序干净退出。

func recurse(depth int, wg *sync.WaitGroup) {
    defer wg.Done()
    if depth == 0 {
        return
    }
    wg.Add(1)
    go recurse(depth - 1, wg)
}

func main() {
    wg := sync.WaitGroup{}
    wg.Add(1)
    go recurse(3, &wg)
    wg.Wait()
}

第二种方式,程序给出“致命错误:所有goroutines都处于睡眠状态-死锁!”

func recurse(depth int, wg sync.WaitGroup) {
    defer wg.Done()
    if depth == 0 {
        return
    }
    wg.Add(1)
    go recurse(depth - 1, wg)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go recurse(3, wg)
    wg.Wait()
}

谁能解释一下第二种方式与第一种方式不同的复杂方式,从而导致“死锁”?

【问题讨论】:

  • 请注意,这个编程错误会被 vet 工具捕获。

标签: go concurrency pass-by-reference pass-by-value


【解决方案1】:

引擎盖下的 WaitGroup 只是一个包含由互斥锁保护的计数器的结构。 Go 以 copy_by_value 方式为函数提供参数。所以 recurse(depth, wg) 函数在按值传递时只接收计数器的副本。像这样:

counter := 5
func(counter){
    counter--
    fmt.Println(counter) //will print "4"
}(counter)
fmt.Println(counter) //will be "5" again

【讨论】:

    猜你喜欢
    • 2021-01-03
    • 2011-08-11
    • 2016-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多