針對Golang 1.9的sync.RWMutex進行分析,與Golang 1.10基本同樣除了將panic
改成了throw
以外其餘的都同樣。
RWMutex是讀寫互斥鎖。鎖能夠由任意數量的讀取器或單個寫入器來保持。 RWMutex的零值是一個解鎖的互斥鎖。
如下代碼均去除race競態檢測代碼bash
源代碼位置:sync\rwmutex.go
ui
type RWMutex struct {
w Mutex // 互斥鎖
writerSem uint32 // 寫鎖信號量
readerSem uint32 // 讀鎖信號量
readerCount int32 // 讀鎖計數器
readerWait int32 // 獲取寫鎖時須要等待的讀鎖釋放數量
}
複製代碼
常量atom
const rwmutexMaxReaders = 1 << 30 // 支持最多2^30個讀鎖
複製代碼
提供寫鎖操做.spa
func (rw *RWMutex) Lock() {
// 競態檢測
if race.Enabled {
_ = rw.w.state
race.Disable()
}
// 使用Mutex鎖
rw.w.Lock()
// Announce to readers there is a pending writer.
r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
// Wait for active readers.
if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
runtime_Semacquire(&rw.writerSem)
}
// 競態檢測
if race.Enabled {
race.Enable()
race.Acquire(unsafe.Pointer(&rw.readerSem))
race.Acquire(unsafe.Pointer(&rw.writerSem))
}
}
複製代碼
提供讀鎖操做,code
func (rw *RWMutex) RLock() {
// 競態檢測
if race.Enabled {
_ = rw.w.state
race.Disable()
}
// 每次goroutine獲取讀鎖時,readerCount+1
// 若是寫鎖已經被獲取,那麼readerCount在-rwmutexMaxReaders與0之間,這時掛起獲取讀鎖的goroutine,
// 若是寫鎖沒有被獲取,那麼readerCount>0,獲取讀鎖,不阻塞
// 經過readerCount判斷讀鎖與寫鎖互斥,若是有寫鎖存在就掛起goroutine,多個讀鎖能夠並行
if atomic.AddInt32(&rw.readerCount, 1) < 0 {
// 將goroutine排到G隊列的後面,掛起goroutine
runtime_Semacquire(&rw.readerSem)
}
// 競態檢測
if race.Enabled {
race.Enable()
race.Acquire(unsafe.Pointer(&rw.readerSem))
}
}
複製代碼
能夠看到RWMutex
實現接口Locker
.接口
type Locker interface {
Lock()
Unlock()
}
複製代碼
而方法RLocker
就是將RWMutex
轉換爲Locker
.隊列
func (rw *RWMutex) RLocker() Locker {
return (*rlocker)(rw)
}
複製代碼
讀寫互斥鎖的實現比較有技巧性一些,須要幾點it
讀鎖不能阻塞讀鎖,引入readerCount實現io
讀鎖須要阻塞寫鎖,直到因此讀鎖都釋放,引入readerSem實現function
寫鎖須要阻塞讀鎖,直到因此寫鎖都釋放,引入wirterSem實現
寫鎖須要阻塞寫鎖,引入Metux實現