RWMutex核心仍是基于Mutex的,若是想了解Mutex的话能够看一下我上一篇写的Mutex的文章RWMutex的特性就是支持并发读。适用于读多写少的场景。并发
type RWMutex struct { w Mutex // 互斥锁 writerSem uint32 // 写锁用的信号量 readerSem uint32 // 读锁用的信号量 readerCount int32 // 当前正在执行读操做的goroutine数量 readerWait int32 // 获取写锁时,当前还持有读锁的goroutine数量 } const rwmutexMaxReaders = 1 << 30
func (rw *RWMutex) Lock() { // 首先调用Mutex的Lock方法获取到锁 rw.w.Lock() // 把readerCount改为负数,这样后续的读操做就会被阻塞 // r 就是当前正在执行读操做的goroutine数量 r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders // 若是当前有正在执行读操做的goroutine // 把r赋值给readerWait if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 { // 获取写锁的goroutine进入休眠,等待被唤醒 runtime_SemacquireMutex(&rw.writerSem, false, 0) } }
func (rw *RWMutex) Unlock() { // 把readerCount改为正数,这样后续读操做就不会被阻塞了 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders) ... // 手动唤醒以前被写锁阻塞的读操做goroutine for i := 0; i < int(r); i++ { runtime_Semrelease(&rw.readerSem, false, 0) } // 释放互斥锁,其余写锁就能够竞争互斥锁了 rw.w.Unlock() }
func (rw *RWMutex) RLock() { ... // readerCount + 1 if atomic.AddInt32(&rw.readerCount, 1) < 0 { // 小于0,说明有其余goroutine获取了写锁, 当前goroutine等待 runtime_SemacquireMutex(&rw.readerSem, false, 0) } ... }
func (rw *RWMutex) RUnlock() { ... // readerCount - 1 // readerCount < 0, 说明其余gouroutine获取了写锁,正在等待还持有读锁的goroutine释放读锁 // readerCount >= 0, 说明没有写锁被阻塞,直接返回就好了 if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 { // 释放读锁 rw.rUnlockSlow(r) } ... } func (rw *RWMutex) rUnlockSlow(r int32) { ... // readerWait - 1 // 判断当前goroutine是否是最后一个释放读锁 if atomic.AddInt32(&rw.readerWait, -1) == 0 { // 唤醒写锁 runtime_Semrelease(&rw.writerSem, false, 1) } }
RWMutex相对Mutex,增长了读锁的控制,就代码逻辑复杂度而言,RWMutex比Mutex要简单不少,对Mutex的流程熟悉的话,很快就能掌握RWMutex的原理ui