詳解golang RWMutex讀寫互斥鎖源碼分析
針對(duì)Golang 1.9的sync.RWMutex進(jìn)行分析,與Golang 1.10基本一樣除了將panic改為了throw之外其他的都一樣。
RWMutex是讀寫互斥鎖。鎖可以由任意數(shù)量的讀取器或單個(gè)寫入器來保持。
RWMutex的零值是一個(gè)解鎖的互斥鎖。
以下代碼均去除race競(jìng)態(tài)檢測(cè)代碼
源代碼位置:sync\rwmutex.go
結(jié)構(gòu)體
type RWMutex struct { w Mutex // 互斥鎖 writerSem uint32 // 寫鎖信號(hào)量 readerSem uint32 // 讀鎖信號(hào)量 readerCount int32 // 讀鎖計(jì)數(shù)器 readerWait int32 // 獲取寫鎖時(shí)需要等待的讀鎖釋放數(shù)量 }
常量
const rwmutexMaxReaders = 1 << 30 // 支持最多2^30個(gè)讀鎖
方法
Lock
提供寫鎖操作.
func (rw *RWMutex) Lock() { // 競(jìng)態(tài)檢測(cè) 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) } // 競(jìng)態(tài)檢測(cè) if race.Enabled { race.Enable() race.Acquire(unsafe.Pointer(&rw.readerSem)) race.Acquire(unsafe.Pointer(&rw.writerSem)) } }
RLock
提供讀鎖操作,
func (rw *RWMutex) RLock() { // 競(jìng)態(tài)檢測(cè) if race.Enabled { _ = rw.w.state race.Disable() } // 每次goroutine獲取讀鎖時(shí),readerCount+1 // 如果寫鎖已經(jīng)被獲取,那么readerCount在-rwmutexMaxReaders與0之間,這時(shí)掛起獲取讀鎖的goroutine, // 如果寫鎖沒有被獲取,那么readerCount>0,獲取讀鎖,不阻塞 // 通過readerCount判斷讀鎖與寫鎖互斥,如果有寫鎖存在就掛起goroutine,多個(gè)讀鎖可以并行 if atomic.AddInt32(&rw.readerCount, 1) < 0 { // 將goroutine排到G隊(duì)列的后面,掛起goroutine runtime_Semacquire(&rw.readerSem) } // 競(jìng)態(tài)檢測(cè) if race.Enabled { race.Enable() race.Acquire(unsafe.Pointer(&rw.readerSem)) } }
RLocker
可以看到RWMutex實(shí)現(xiàn)接口Locker.
type Locker interface { Lock() Unlock() }
而方法RLocker就是將RWMutex轉(zhuǎn)換為L(zhǎng)ocker.
func (rw *RWMutex) RLocker() Locker { return (*rlocker)(rw) }
總結(jié)
讀寫互斥鎖的實(shí)現(xiàn)比較有技巧性一些,需要幾點(diǎn)
- 讀鎖不能阻塞讀鎖,引入readerCount實(shí)現(xiàn)
- 讀鎖需要阻塞寫鎖,直到所以讀鎖都釋放,引入readerSem實(shí)現(xiàn)
- 寫鎖需要阻塞讀鎖,直到所以寫鎖都釋放,引入wirterSem實(shí)現(xiàn)
- 寫鎖需要阻塞寫鎖,引入Metux實(shí)現(xiàn)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
golang實(shí)現(xiàn)微信小程序商城后臺(tái)系統(tǒng)(moshopserver)
這篇文章主要介紹了golang實(shí)現(xiàn)微信小程序商城后臺(tái)系統(tǒng)(moshopserver),本文通過截圖實(shí)例代碼的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02go項(xiàng)目實(shí)現(xiàn)mysql接入及web?api的操作方法
這篇文章主要介紹了go項(xiàng)目實(shí)現(xiàn)mysql接入以及web api,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08Golang實(shí)現(xiàn)按比例切分流量的示例詳解
我們?cè)谶M(jìn)行灰度發(fā)布時(shí),往往需要轉(zhuǎn)發(fā)一部分流量到新上線的服務(wù)上,進(jìn)行小規(guī)模的驗(yàn)證,隨著功能的不斷完善,我們也會(huì)逐漸增加轉(zhuǎn)發(fā)的流量,這就需要按比例去切分流量,那么如何實(shí)現(xiàn)流量切分呢,接下來小編就給大家詳細(xì)的介紹一下實(shí)現(xiàn)方法,需要的朋友可以參考下2023-09-09golang 64位linux環(huán)境下編譯出32位程序操作
這篇文章主要介紹了golang 64位linux環(huán)境下編譯出32位程序操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12Golang打印復(fù)雜結(jié)構(gòu)體兩種方法詳解
在?Golang?語(yǔ)言開發(fā)中,我們經(jīng)常會(huì)使用結(jié)構(gòu)體類型,如果我們使用的結(jié)構(gòu)體類型的變量包含指針類型的字段,我們?cè)谟涗浫罩镜臅r(shí)候,指針類型的字段的值是指針地址,將會(huì)給我們?debug?代碼造成不便2022-10-10Golang RSA生成密鑰、加密、解密、簽名與驗(yàn)簽的實(shí)現(xiàn)
RSA 是最常用的非對(duì)稱加密算法,本文主要介紹了Golang RSA生成密鑰、加密、解密、簽名與驗(yàn)簽的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11VScode下配置Go語(yǔ)言開發(fā)環(huán)境(2023最新)
在VSCode中配置Golang開發(fā)環(huán)境是非常簡(jiǎn)單的,本文主要記錄了Go的安裝,以及給vscode配置Go的環(huán)境,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10淺析Go語(yǔ)言bitset的實(shí)現(xiàn)原理
bitset包是一個(gè)將非負(fù)整數(shù)映射到布爾值的位的集合,這篇文章主要通過開源包bitset來為大家分析一下位集合的設(shè)計(jì)和實(shí)現(xiàn),感興趣的可以學(xué)習(xí)一下2023-08-08手把手帶你走進(jìn)Go語(yǔ)言之循環(huán)語(yǔ)句
在不少實(shí)際問題中有許多具有規(guī)律性的重復(fù)操作,因此在程序中就需要重復(fù)執(zhí)行某些語(yǔ)句。一組被重復(fù)執(zhí)行的語(yǔ)句稱之為循環(huán)體,能否繼續(xù)重復(fù),決定循環(huán)的終止條件,本文給大家介紹的非常詳細(xì),跟著小編往下看吧2021-09-09