【发布时间】:2017-12-31 13:39:03
【问题描述】:
我有一个 (LRU) 缓存对象,但遇到了死锁……这怎么可能?
type cache struct {
mutex *sync.Mutex
...
}
func (this *cache) Init() { // guaranteed to be called once, in main()
this.mutex = &sync.Mutex{}
}
func (this *cache) f1() {
// Pattern for accessing mute, at the top of any function of 'cache' where needed.
this.mutex.Lock()
defer this.mutex.Unlock()
...
}
func (this *cache) f2() {
this.mutex.Lock()
defer this.mutex.Unlock()
...
}
在每个出现mutex 的函数中,只能使用这种模式访问它。
然而......我遇到了僵局。这怎么可能?
注意:这段代码已经在生产服务器上运行了 10 个月,这是我第一次得到它。
编辑:因此 f1() 可以(间接)调用 f2() 以根据答案获得死锁。没错,但在我的代码中这不会发生,所以我真的很想知道
【问题讨论】:
-
f1 是否保证退出?它会调用其他锁定互斥锁的函数吗?
-
如果
cache的一个方法调用另一个方法,并且都包含Lock()调用,则很容易发生死锁。 -
如上,取决于
f1()的作用。此外,您无需创建新的互斥体并使用Init()。只需在结构中使用sync.Mutex而不是*sync,Mutex,因为设计的零值是有效的未锁定互斥体。 -
你在比赛检测器下运行过这个吗?我不确定它是否可以检测到可能的多次锁定尝试,但它可能会揭示一些东西......
-
@Thomas 方法不需要直接相互调用。可能是
cache.f1()调用foo()这是一个“独立”函数,如果foo()调用cache.f2(),我们处于同样的死锁状态。请参阅编辑后的答案。如果你的代码中甚至不存在这样的传递调用,那么你需要发布一个minimal reproducible example,否则它就会偏离主题。