这是死锁吗?为什么执行程序说它是死锁?

问题描述 投票:-3回答:1

当我运行此程序时:

var mu = sync.Mutex{}
func f2() {
    mu.Lock()
    fmt.Println("call f2...")
}

func main() {
    go f2()
    time.Sleep(time.Second * 2)
    mu.Lock()
    fmt.Println("get lock in main")
}

我得到此输出:

call f2...
fatal error: all goroutines are asleep - deadlock!

playground link

我们知道有四个条件具有死锁,一个是Wait For condition,它要求至少有两种资源才能获得,但是这里只有一种资源。

所以这是一个死锁吗?

我知道退出了很多并发编程。只是在这种情况下,只有f2()不会释放锁定,并且也不是wikipedia defines的死锁。

go deadlock
1个回答
2
投票

[您的代码中有一个互斥锁,该互斥锁已锁定在2个goroutine中:在main goroutine中,而另一个在执行f2()中。

如果f2()越早锁定互斥锁,主goroutine将永远无法再次锁定它,因此这是一个死锁。并且由于您在启动main()(作为goroutine)和锁定互斥锁之间在f2中使用了2秒钟的睡眠,因此您将观察到此死锁像总是一样

[请注意,如果计划将main goroutine首先锁定互斥锁,则不会发生死锁,因为main()函数可以继续运行,并且一旦返回,应用程序将终止(不等待f2()完)。但同样,由于您插入了睡眠,您将可能永远不会得到此结果。

我使用了“ like always”“ likely never”]这句话是因为尽管goroutine调度程序的睡眠指令是一个很好的调度点,但它不是同步点。运行时将安排其他goroutine在goroutine处于睡眠状态时运行(为什么不这样做),但这不能保证。同步点可以为您提供保证(例如通道通信,锁定,sync.Once等)。在The Go Memory Model中有详细说明。

© www.soinside.com 2019 - 2024. All rights reserved.