使用 The Little Go Book 中的单锁解释死锁
Explaining deadlocks with a single lock from The Little Go Book
我正在阅读 The Little Go Book。
第 76 页演示了如何使用单锁死锁:
var (
lock sync.Mutex
)
func main() {
go func() { lock.Lock() }()
time.Sleep(time.Millisecond * 10)
lock.Lock()
}
运行 正如作者所解释的那样,这会导致死锁。但是,我不明白的是为什么。
我把程序改成这样:
var (
lock sync.Mutex
)
func main() {
go func() { lock.Lock() }()
lock.Lock()
}
我的预期是仍然会引发死锁。但事实并非如此。
有人可以向我解释一下这里发生了什么吗?
我能想到的唯一可以解释这一点的情况如下(但这是猜测):
第一个例子
- 锁在第一个goroutine中获取
- 调用
time.Sleep()
确保获得锁
main
函数试图获取锁导致死锁
- 程序退出
第二个例子
- 锁是在第一个 goroutine 中获取的,但这需要一些时间 (??)
- 由于没有延迟,
main
函数在 goroutine 可以 之前获取锁
- 程序退出
在第一个例子中,main sleep 足够长的时间让子 goroutine 有机会启动并获取锁。然后那个 goroutine 会在不释放锁的情况下愉快地退出。
当 main 恢复其控制流时,共享互斥量已被锁定,因此下一次获取它的尝试将永远阻塞。由于此时 main 是唯一存活的例程,因此永远阻塞会导致死锁。
在第二个例子中,没有调用time.Sleep
,main直接获取锁。这成功了,所以 main 继续并退出。子 goroutine 会 然后永远阻塞,但是由于 main 已经退出,程序就终止了,没有死锁。
顺便一提,即使main没有退出,只要至少有一个goroutine没有阻塞,就不会出现死锁。为此,time.Sleep
不是阻塞操作,它只是暂停执行指定的持续时间。
go
显示当所有 goroutines
(包括主要)都在睡觉时出现死锁错误。
在您的第一个示例中,内部 goroutine
在他调用 mutex.Lock()
后执行并终止。然后主 goroutine 再次尝试锁定,但它会 asleep
等待占用锁的机会。所以现在我们让程序中的所有 goroutines(主要的)处于睡眠模式,这将导致死锁错误!
了解这一点很重要,因为可能会发生死锁,但如果仍有 运行 goroutine,它不会总是显示错误。这主要是在生产中会发生什么。只有当整个程序陷入死锁时才会报错。
我正在阅读 The Little Go Book。
第 76 页演示了如何使用单锁死锁:
var (
lock sync.Mutex
)
func main() {
go func() { lock.Lock() }()
time.Sleep(time.Millisecond * 10)
lock.Lock()
}
运行 正如作者所解释的那样,这会导致死锁。但是,我不明白的是为什么。
我把程序改成这样:
var (
lock sync.Mutex
)
func main() {
go func() { lock.Lock() }()
lock.Lock()
}
我的预期是仍然会引发死锁。但事实并非如此。
有人可以向我解释一下这里发生了什么吗?
我能想到的唯一可以解释这一点的情况如下(但这是猜测):
第一个例子
- 锁在第一个goroutine中获取
- 调用
time.Sleep()
确保获得锁 main
函数试图获取锁导致死锁- 程序退出
第二个例子
- 锁是在第一个 goroutine 中获取的,但这需要一些时间 (??)
- 由于没有延迟,
main
函数在 goroutine 可以 之前获取锁
- 程序退出
在第一个例子中,main sleep 足够长的时间让子 goroutine 有机会启动并获取锁。然后那个 goroutine 会在不释放锁的情况下愉快地退出。
当 main 恢复其控制流时,共享互斥量已被锁定,因此下一次获取它的尝试将永远阻塞。由于此时 main 是唯一存活的例程,因此永远阻塞会导致死锁。
在第二个例子中,没有调用time.Sleep
,main直接获取锁。这成功了,所以 main 继续并退出。子 goroutine 会 然后永远阻塞,但是由于 main 已经退出,程序就终止了,没有死锁。
顺便一提,即使main没有退出,只要至少有一个goroutine没有阻塞,就不会出现死锁。为此,time.Sleep
不是阻塞操作,它只是暂停执行指定的持续时间。
go
显示当所有 goroutines
(包括主要)都在睡觉时出现死锁错误。
在您的第一个示例中,内部 goroutine
在他调用 mutex.Lock()
后执行并终止。然后主 goroutine 再次尝试锁定,但它会 asleep
等待占用锁的机会。所以现在我们让程序中的所有 goroutines(主要的)处于睡眠模式,这将导致死锁错误!
了解这一点很重要,因为可能会发生死锁,但如果仍有 运行 goroutine,它不会总是显示错误。这主要是在生产中会发生什么。只有当整个程序陷入死锁时才会报错。