以下代码执行结果:
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()已经因为写锁等待而卡住导致 循环等待:写锁等读锁,读锁等写锁