Alexu
发布于 2025-05-21 / 1 阅读
0
0

Golang RWLock相关问题

以下代码执行结果:

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,原因描述

关键问题:写锁饥饿 + 读锁嵌套

  1. A() 先获取读锁(RLock

    • 此时允许其他读操作,但会阻塞写操作(Lock

  2. 主 goroutine 2 秒后尝试获取写锁(Lock

    • 由于 A() 持有读锁,写操作被阻塞

    • 写锁会等待所有现有的读锁释放后才能获取

  3. B() 休眠 5 秒后调用 C()

    • C() 尝试获取读锁(RLock

    • Go 的 RWMutex 是写优先的:当有写锁等待时,新的读锁会被阻塞(防止写锁饥饿)

    • 因此 C()RLock 会一直等待写锁完成,但写锁又在等 A() 的读锁释放

  4. A() 的读锁需要等 B()C() 返回后才能释放

    • C() 已经因为写锁等待而卡住

    • 导致 循环等待:写锁等读锁,读锁等写锁


时间线分析

时间

主 goroutine

goroutine A

0s

启动 A()

A() 获取读锁(RLock)

2s

尝试获取写锁(Lock)阻塞

执行 B(),休眠 5 秒

5s

仍然阻塞

B() 调用 C()

5s

C() 尝试读锁(RLock)阻塞

死锁

死锁


评论