go - 如何防止递归函数死锁?

标签 go deadlock

我有一个递归函数,我将锁定并改变其内部状态,但是,它会导致死锁。如何实现这样的递归函数而不出现死锁?

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/

相关文章:

go - 如何在golang的sql.open函数中调用变量

go - "channel1 <- <-channel2"是做什么的?

string - Golang : Issues replacing newlines in a string from a text file

c - pthreads - pthread_cond_wait 上的死锁

c++ - 如何避免临界区和 SendMessage 之间的这种死锁?

sql - 我怎样才能避免 Postgres 中的这种三向死锁?

go - 如何理解 exec.cmd 是否被取消

go - Go 是否有任何 SFTP 或 SSH 库?

c# - 如何摆脱 SQL Server 2005 和 C# 应用程序中的死锁?

multithreading - 为什么左/右顺序在哲学家晚餐的指挥解决方案中很重要?