sync.Mutex / RWMute原理
sync.Mutex / RWMute原理
sync.Mutex
Go 的 sync.Mutex 底层主要由 state + semaphore 两个字段组成。
1
2
3
4
type Mutex struct {
state int32 // 状态
sema uint32 // 信号量
}
加锁时首先通过 CAS(Compare and Swap,比较并交换) 尝试抢锁,如果失败会进行 短暂自旋,自旋仍失败则通过 信号量机制将 goroutine 挂起并加入等待队列。
解锁时会修改 state 状态,并通过信号量机制唤醒等待的 goroutine。
为了防止锁饥饿,Go 在 1.9 之后引入了 正常(公平) 和 饥饿 两种模式,在等待时间超过 1ms 时进入饥饿模式,锁会直接交给等待队列第一个 goroutine。
sync.RWMute
1
2
3
4
5
6
7
type RWMutex struct {
w Mutex // 写锁(本质还是 Mutex)
readerCount int32 // 当前读者数量
readerWait int32 // 等待释放的读者数
writerSem uint32 // 写等待信号量
readerSem uint32 // 读等待信号量
}
RWMute是通过Mutex + 计数器 + 读/写信号量实现的.
如何解决写饥饿问题?
- 抢占写锁 -> 阻止新读锁加锁 -> 等待已有读锁结束
什么情况下使用RWMute,什么情况下使用Mutex
- RWMute:适用读多写少场景。
- Mutex:适用低并发,读写平均场景。
因为RWMute频繁加写锁开销比Mutex大,RWMute的写锁需要解决写饥饿。
This post is licensed under CC BY 4.0 by the author.