以下代码执行结果:
var mu sync.RWMutex
var count int
func main() {
go A()
time.Sleep(2 * time.Second)
mu.Lock()
defer mu.Unlock()
count++
fmt.Println(count)
}
func A() {
mu.RLock()
defer mu.RUnlock()
B()
}
func B() {
time.Sleep(5 * time.Second)
C()
}
func C() {
mu.RLock()
defer mu.RUnlock()
}
执行的结果是:
A. 不能编译;
B. 输出 1;
C. 程序 hang 住;
D. fatal error;
结果是C,原因描述
关键问题:写锁饥饿 + 读锁嵌套
A()
先获取读锁(RLock
)此时允许其他读操作,但会阻塞写操作(
Lock
)
主 goroutine 2 秒后尝试获取写锁(
Lock
)由于
A()
持有读锁,写操作被阻塞写锁会等待所有现有的读锁释放后才能获取
B()
休眠 5 秒后调用C()
C()
尝试获取读锁(RLock
)Go 的
RWMutex
是写优先的:当有写锁等待时,新的读锁会被阻塞(防止写锁饥饿)因此
C()
的RLock
会一直等待写锁完成,但写锁又在等A()
的读锁释放
A()
的读锁需要等B()
和C()
返回后才能释放但
C()
已经因为写锁等待而卡住导致 循环等待:写锁等读锁,读锁等写锁