具有匿名互斥锁和结构的死锁

时间:2018-11-26 14:32:23

标签: go struct mutex deadlock embedding

假设我有以下两种结构:

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,则没有死锁。但是我不知道为什么这么重要。任何人都可以解释这种行为吗?

https://play.golang.org/p/UVi_WLWeGmi

1 个答案:

答案 0 :(得分:5)

发生死锁的原因是因为您的代码将两次调用同一互斥量的Lock()方法,这是一个阻塞操作。

解释位于Spec: Selectors:

  

以下规则适用于选择器:

     
      
  1. 对于类型为xT(其中*T不是指针或接口类型)的值Tx.f表示位于在T中{strong>最浅的深度,其中有一个f。如果深度不完全是one f,则选择器表达式是非法的。
  2.   

这是什么意思?

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个不同的互斥体;它们是独立的,因此第二个锁不会被阻止(其互斥锁尚未锁定)。