死锁与匿名互斥和结构

von*_*aka -1 struct mutex deadlock embedding go

假设我有这两种结构:

type A struct {
    Mutex sync.Mutex
    i int
}

type B struct {
    A
    sync.Mutex
}
Run Code Online (Sandbox Code Playgroud)

现在,当我试图锁定B然后A我遇到了僵局:

var b B
b.Lock()
b.Mutex.Lock()
b.Mutex.Unlock()
b.Unlock()
Run Code Online (Sandbox Code Playgroud)

我想通了,这是与结构的互斥体的名字相关A,例如,有是,如果我将其命名为无僵局Mutexx,而不是Mutex.但我不知道为什么这很重要.有人可以解释一下这种行为吗?

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

icz*_*cza 5

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

解释在于Spec:选择器:

以下规则适用于选择器:

  1. 对于值x类型的T*T其中T不是指针或接口类型,x.f表示在域或方法的深度T,其中有这样一个f.如果没有一个f深度最浅的选择器表达式是非法的.

这是什么意思?

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().但是再次根据引用的规则,它将表示最浅深度的场/方法,即B.Mutex.Lock().

所以这段代码:

b.Lock()
b.Mutex.Lock()
Run Code Online (Sandbox Code Playgroud)

将调用Lock()相同的方法Mutex两次,这是struct 的嵌入B.Mutex字段B.第二个调用将阻止,因为互斥锁已被锁定.

当你重命名A.Mutex为eg A.Mutexx,然后你写:

b.Lock()
b.Mutexx.Lock()
Run Code Online (Sandbox Code Playgroud)

第一个b.Lock()呼叫是指B.Mutex.Lock(),第二个b.Mutexx.Lock()呼叫是指B.A.Mutexx.Lock()呼叫,因此它们锁定2个不同的,不同的互斥锁; 它们是独立的,因此第二个锁不会阻塞(它的互斥锁尚未锁定).

  • @vonaka那是在[规范:结构类型:](https://golang.org/ref/spec#Struct_types)_"用类型声明但没有显式字段名称的字段称为嵌入字段.嵌入字段必须被指定为类型名称`T`或指向非接口类型名称`*T`的指针,而`T`本身可能不是指针类型.**非限定类型名称作为字段名称.**"_ (2认同)