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