假设我有以下两种结构:
docker build
现在,当我尝试锁定type A struct {
Mutex sync.Mutex
i int
}
type B struct {
A
sync.Mutex
}
然后锁定B
时,出现了死锁:
A
我发现这与结构var b B
b.Lock()
b.Mutex.Lock()
b.Mutex.Unlock()
b.Unlock()
的互斥锁的名称有关,例如,如果我将其命名为A
而不是Mutexx
,则没有死锁。但是我不知道为什么这么重要。任何人都可以解释这种行为吗?
答案 0 :(得分:5)
发生死锁的原因是因为您的代码将两次调用同一互斥量的Lock()
方法,这是一个阻塞操作。
解释位于Spec: Selectors:
以下规则适用于选择器:
- 对于类型为
x
或T
(其中*T
不是指针或接口类型)的值T
,x.f
表示位于在T
中{strong>最浅的深度,其中有一个f
。如果深度不完全是onef
,则选择器表达式是非法的。
这是什么意思?
在B
中,您同时嵌入了sync.Mutex
和值A
,并且A
也嵌入了sync.Mutex
。
在编写B.Mutex
时,它可能引用直接嵌入的B.Mutex
字段(不合格的类型名称充当字段名称),并且可以也引用{ {1}}(因为B.A.Mutex
字段嵌入在A
中),但是根据上面引用的规则,它将表示最浅深度的字段/方法,是B
。
类似地,B.Mutex
可以引用b.Lock()
,也可以引用B.Mutex.Lock()
。但是再次根据引用的规则,它将表示最浅深度处的字段/方法,即B.A.Mutex.Lock()
。
所以这段代码:
B.Mutex.Lock()
将两次调用同一b.Lock()
b.Mutex.Lock()
的{{1}}方法,这是Lock()
结构的嵌入Mutex
字段。由于互斥已被锁定,因此第二个调用将被阻止。
将B.Mutex
重命名为例如B
,然后输入:
A.Mutex
第一个A.Mutexx
调用指向b.Lock()
b.Mutexx.Lock()
,第二个b.Lock()
调用指向B.Mutex.Lock()
调用,因此它们锁定2个不同的互斥体;它们是独立的,因此第二个锁不会被阻止(其互斥锁尚未锁定)。