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



当我运行这个程序时:

package main
import (
"fmt"
"sync"
"time"
)
var mu = new(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!

游乐场连接。

正如我们所知,有四个条件可以拥有死锁,一个是Hold and wait or resource holding,它要求至少有两种资源可以获得,但这里只有一种资源。

这是不是一把死锁?

我知道退出了很多并发编程。只是在这种情况下,只有f2()没有释放锁,这并不是维基百科定义的死锁。

请注意:"goroutine死锁"(这就是您所经历的(是指所有现有goroutine都被阻塞并且无法单独进行的状态。存在多个现有goroutine或只有一个goroutine都无关紧要。如果go运行时检测到goroutine死锁,则终止应用程序(让应用程序永远挂起是没有意义的,它永远不会恢复,这在goroutine僵局的定义中(。


您的代码中有一个互斥锁,它被锁定在两个goroutine中:在maingoroutine和执行f2()的goroutine。

如果f2()提前到达锁定互斥体的点,那么主goroutine将永远无法再次锁定它,因为没有人解锁互斥体,所以这就是死锁。因为f2()将在锁定和打印后返回,并且它的goroutine将结束,并且唯一剩余的maingoroutine在尝试锁定mu时被阻止。由于在main()中,在启动f2(作为goroutine(和锁定互斥体之间使用了2秒的睡眠,因此您将像往常一样观察到这种死锁。

请注意,如果maingoroutine将被调度为首先锁定互斥,则不会发生死锁,因为main()函数可以继续运行,并且一旦返回,应用程序将终止(不等待f2()完成(。但同样,由于你插入的睡眠,你很可能永远不会得到这个结果。

我使用了短语"像往常一样">"可能永远不会">,因为尽管睡眠指令是goroutine调度器的一个很好的调度点,但它不是同步点。运行时会安排其他goroutine在goroutine处于睡眠状态时运行(为什么不这样做(,但这并不能保证。同步点可以为您提供保证(如信道通信、锁、sync.Once等(。这在Go内存模型中有详细说明。

相关内容

最新更新