日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Go】sync.RWMutex源码分析

發(fā)布時間:2023/12/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Go】sync.RWMutex源码分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

RWMutex

讀寫鎖相較于互斥鎖有更低的粒度,它允許并發(fā)讀,因此在讀操作明顯多于寫操作的場景下能減少鎖競爭的次數(shù),提高程序效率。

type RWMutex struct {w Mutex // held if there are pending writerswriterSem uint32 // semaphore for writers to wait for completing readersreaderSem uint32 // semaphore for readers to wait for completing writersreaderCount int32 // number of pending readersreaderWait int32 // number of departing readers }

RWMutex 結(jié)構(gòu)體中包含五個字段,分別表示:

  • w: 復(fù)用互斥鎖
  • writerSem 和 readerSem: 用于寫等待讀和讀等待寫的信號量
  • readerCount:
  • readerWait: 等待寫鎖釋放的讀者數(shù)量

讀鎖

RLock

當(dāng)有 goroutine 寫時,是不允許讀的,這時會把 readerCount 設(shè)置為負(fù),這時讀 goroutine 應(yīng)該被阻塞

func (rw *RWMutex) RLock() {if atomic.AddInt32(&rw.readerCount, 1) < 0 {// 阻塞讀runtime_SemacquireMutex(&rw.readerSem, false, 0)} }

RUnlock

讀鎖解鎖時只需要將 readerCount - 1, 如果結(jié)果小于零,說明:

  • 原來 readerCount == 0 || readerCount == -rwmutexMaxReaders, 對未加鎖的對象執(zhí)行了解鎖操作
  • 原來 readerCount < 0, 有正在執(zhí)行的寫操作
  • func (rw *RWMutex) RUnlock() {if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {// Outlined slow-path to allow the fast-path to be inlinedrw.rUnlockSlow(r)} }func (rw *RWMutex) rUnlockSlow(r int32) {if r+1 == 0 || r+1 == -rwmutexMaxReaders {race.Enable()throw("sync: RUnlock of unlocked RWMutex")}// 所有讀操作結(jié)束后,觸發(fā)寫的寫信號量if atomic.AddInt32(&rw.readerWait, -1) == 0 {// The last reader unblocks the writer.runtime_Semrelease(&rw.writerSem, false, 1)} }

    寫鎖

    Lock

    func (rw *RWMutex) Lock() {// 獲取互斥寫鎖rw.w.Lock()// 阻塞讀r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders// 如果有人在讀,需要等待讀鎖釋放if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {// 阻塞等待讀鎖釋放runtime_SemacquireMutex(&rw.writerSem, false, 0)} }

    Lock 會先通過互斥鎖阻塞寫操作,然后禁止讀鎖獲取,等待已經(jīng)持有讀鎖的 goroutine 釋放讀鎖,這樣可以避免連續(xù)的寫操作使讀陷入饑餓。

    Unlock

    func (rw *RWMutex) Unlock() {// 重新允許讀鎖獲取r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)if r >= rwmutexMaxReaders {race.Enable()throw("sync: Unlock of unlocked RWMutex")}// 觸發(fā)等待中的寫鎖的信號量for i := 0; i < int(r); i++ {runtime_Semrelease(&rw.readerSem, false, 0)}// 互斥鎖解鎖rw.w.Unlock() }

    總結(jié)

    在極端情況下:

    • 如果完全沒有寫,讀鎖加鎖只是將 readerCount 加一,解鎖只是將其減一,不存在鎖競爭。
    • 如果只有寫,加鎖和解鎖都比互斥鎖多了一個對 readerCount 取反操作

    在一般情況下,讀鎖在獲取鎖前會檢查 readerCount, 如果為負(fù),說明有人在寫,則進(jìn)入阻塞狀態(tài),等待 readerSem 的信號,寫鎖獲取鎖在得到互斥鎖后會先設(shè)置 readerCount 為負(fù),阻止新的讀者獲取讀鎖,然后需要等待所有已經(jīng)持有讀鎖的 goroutine 釋放讀鎖,這里使用的是 readerWait ,當(dāng) readerCount 為負(fù)時,如果讀鎖被釋放,該量就會減一,當(dāng) readerWait == 0 時,則說明所有在寫鎖獲取之前獲得的讀鎖都被釋放了,最后一個釋放的讀鎖會通過 writerSem 通知寫對象。

    寫鎖釋放時,需要通過 readerSem 信號觸發(fā)所有阻塞中的寫對象。

    總結(jié)

    以上是生活随笔為你收集整理的【Go】sync.RWMutex源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。