匿名互斥体和结构的死锁
Deadlock with anonymous mutex and struct
假设我有这两个结构:
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()
我发现这和struct的mutex的名字有关A
,比如我把它命名为Mutexx
而不是Mutex
就不会出现死锁.但我不知道为什么这很重要。谁能解释一下这种行为?
死锁的原因是因为你的代码会两次调用同一个mutex的Lock()
方法,这是一个阻塞操作。
The following rules apply to selectors:
- For a value
x
of type T
or *T
where T
is not a pointer or interface type, x.f
denotes the field or method at the shallowest depth in T
where there is such an f
. If there is not exactly one f
with shallowest depth, the selector expression is illegal.
这是什么意思?
在 B
中,您同时嵌入了 sync.Mutex
和 A
的值,并且 A
还嵌入了 sync.Mutex
.
写B.Mutex
时,可以引用直接嵌入的B.Mutex
字段(非限定类型名作为字段名),可以也指B.A.Mutex
(因为A
字段嵌入在B
中),但是根据上面引用的规则,它会表示处的字段/方法最浅 深度,即B.Mutex
.
同样,b.Lock()
可以引用 B.Mutex.Lock()
,也可以引用 B.A.Mutex.Lock()
。但同样根据引用的规则,它将表示 shallowest 深度的字段/方法,即 B.Mutex.Lock()
.
所以这段代码:
b.Lock()
b.Mutex.Lock()
会调用同一个Mutex
的Lock()
方法两次,也就是B
结构体的内嵌B.Mutex
字段。第二次调用将阻塞,因为互斥量已被锁定。
当您将 A.Mutex
重命名为例如A.Mutexx
,然后你写:
b.Lock()
b.Mutexx.Lock()
第一个 b.Lock()
调用引用 B.Mutex.Lock()
,第二个 b.Mutexx.Lock()
调用引用 B.A.Mutexx.Lock()
调用,因此它们锁定了 2 个不同的互斥锁;它们是独立的,所以第二个锁不会阻塞(它的互斥量还没有被锁定)。
假设我有这两个结构:
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()
我发现这和struct的mutex的名字有关A
,比如我把它命名为Mutexx
而不是Mutex
就不会出现死锁.但我不知道为什么这很重要。谁能解释一下这种行为?
死锁的原因是因为你的代码会两次调用同一个mutex的Lock()
方法,这是一个阻塞操作。
The following rules apply to selectors:
- For a value
x
of typeT
or*T
whereT
is not a pointer or interface type,x.f
denotes the field or method at the shallowest depth inT
where there is such anf
. If there is not exactly onef
with shallowest depth, the selector expression is illegal.
这是什么意思?
在 B
中,您同时嵌入了 sync.Mutex
和 A
的值,并且 A
还嵌入了 sync.Mutex
.
写B.Mutex
时,可以引用直接嵌入的B.Mutex
字段(非限定类型名作为字段名),可以也指B.A.Mutex
(因为A
字段嵌入在B
中),但是根据上面引用的规则,它会表示处的字段/方法最浅 深度,即B.Mutex
.
同样,b.Lock()
可以引用 B.Mutex.Lock()
,也可以引用 B.A.Mutex.Lock()
。但同样根据引用的规则,它将表示 shallowest 深度的字段/方法,即 B.Mutex.Lock()
.
所以这段代码:
b.Lock()
b.Mutex.Lock()
会调用同一个Mutex
的Lock()
方法两次,也就是B
结构体的内嵌B.Mutex
字段。第二次调用将阻塞,因为互斥量已被锁定。
当您将 A.Mutex
重命名为例如A.Mutexx
,然后你写:
b.Lock()
b.Mutexx.Lock()
第一个 b.Lock()
调用引用 B.Mutex.Lock()
,第二个 b.Mutexx.Lock()
调用引用 B.A.Mutexx.Lock()
调用,因此它们锁定了 2 个不同的互斥锁;它们是独立的,所以第二个锁不会阻塞(它的互斥量还没有被锁定)。