我有一个递归函数,我将锁定并改变其内部状态,但是,它会导致死锁。如何实现这样的递归函数而不出现死锁?
package main
import (
"fmt"
"sync"
)
type runner struct {
sync.Mutex
value int
}
func (r *runner) decrement() {
r.Lock()
defer r.Unlock()
if r.value == 0 {
return
}
r.value--
r.decrement()
}
func main() {
r := runner{
value: 10,
}
r.decrement()
fmt.Printf("r: %v\n", r.value)
}
预计运行上面的代码会打印r: 0
,但实际上出现了死锁:
fatal error: all goroutines are asleep - deadlock!
最佳答案
此类问题的典型解决方案是 reentrant mutex 。然而,Go 团队的 Russ Cox 对于原因有一个很好的论据 reentrant mutexes are a bad idea .
在这种情况下,您不想推迟解锁。相反,您应该锁定和解锁所需的最少部分。
func (r *runner) decrement() {
r.Lock()
if r.value == 0 {
r.Unlock()
return
}
r.value--
r.Unlock()
r.decrement()
}
这解决了两个问题:一,它(略微)提高了代码并发运行的能力,方法是不对不需要锁定的事物进行锁定,二,它确保如果您重新输入 decrement()
,不存在会导致死锁的未完成锁定。
关于go - 如何防止递归函数死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58651496/