欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

go中sync.RWMutex的源碼解讀

 更新時(shí)間:2024年04月03日 15:25:56   作者:Q_X_Q 慶  
本文主要介紹了go中sync.RWMutex的源碼解讀,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

簡介

簡述sync包中讀寫鎖的源碼。 (go -version 1.21)

讀寫鎖(RWMutex)是一種并發(fā)控制機(jī)制,用于在多個(gè) goroutine 之間對(duì)共享資源進(jìn)行讀寫操作。它提供了兩種鎖定方式:讀鎖和寫鎖。
讀鎖(RLock):多個(gè) goroutine 可以同時(shí)持有讀鎖,而不會(huì)阻塞彼此。只有當(dāng)沒有寫鎖被持有時(shí),讀鎖才會(huì)被授予。這樣可以實(shí)現(xiàn)多個(gè) goroutine 并發(fā)地讀取共享資源,提高程序性能。
寫鎖(Lock):寫鎖是排它的,當(dāng)某個(gè) goroutine 持有寫鎖時(shí),其他所有 goroutine 都無法獲得讀鎖或?qū)戞i。這是為了確保在寫入共享資源時(shí),沒有其他 goroutine 在讀或?qū)懺撡Y源。

寫鎖是排他性的 :
(假設(shè)寫鎖不是排他性的, 新的讀鎖可以被獲取) 反證:(多個(gè)寫鎖的情況下就不聊了)
現(xiàn)在有 一個(gè)goroutine1 獲取讀鎖; 一個(gè) goroutine2 獲取寫鎖,但沒有寫鎖被其他goroutine持有
然后有個(gè)goroutine3 想獲取讀鎖,在假設(shè)的條件下 goroutine3 就會(huì)獲取到讀鎖, 會(huì)導(dǎo)致goroutine2 無法獲取寫鎖, 極端情況下會(huì)導(dǎo)致goroutine2 一直獲取不到寫鎖 ---- 寫鎖饑餓
所以 為了讀寫公平, 還是把寫鎖優(yōu)先級(jí)提高, 在寫鎖的情況下, 新的讀鎖無法被獲取。

源碼

結(jié)構(gòu)

// RWMutex 結(jié)構(gòu)體包含了用于讀寫互斥鎖的各種狀態(tài)和信號(hào)量。在 RWMutex 中,多個(gè) goroutine 可以同時(shí)持有讀鎖,
// 但只有一個(gè) goroutine 可以持有寫鎖。RWMutex 的實(shí)現(xiàn)確保了在寫鎖等待的情況下,新的讀鎖無法被獲取,
// 從而防止了讀鎖長時(shí)間等待
type RWMutex struct {
    w           Mutex        // 用于寫鎖的互斥鎖
    writerSem   uint32       // 寫鎖的信號(hào)量,用于等待讀鎖完成
    readerSem   uint32       // 讀鎖的信號(hào)量,用于等待寫鎖完成
    readerCount atomic.Int32 // 讀者持有讀者鎖的數(shù)量
    readerWait  atomic.Int32 // 寫者等待讀鎖的數(shù)量
}
// readerCount 
// 當(dāng)讀者加鎖時(shí), readerCount  +1 
// 當(dāng)讀者解鎖時(shí), readerCount  -1
// 當(dāng) readerCount 大于 0 時(shí),表示有讀者持有讀鎖。
// 如果 readerCount 等于 0,則表示當(dāng)前沒有讀者持有讀鎖。
// 當(dāng) readerCount 等于 0 時(shí),其他寫者可以嘗試獲取寫鎖
// 當(dāng) readerCount < 0 , 說明有寫者在等待, 讀者需要等待寫者釋放寫鎖
// readerWait(寫者等待讀鎖的數(shù)量):
// 當(dāng)寫者嘗試獲取寫鎖,但當(dāng)前有讀者持有讀鎖時(shí),寫者會(huì)被阻塞,并且 readerWait 會(huì)增加。
// 當(dāng)讀者釋放讀鎖時(shí),如果有寫者在等待讀鎖,readerWait 會(huì)減少,并且可能喚醒等待的寫者
// readerCount > 0:表示有讀者持有讀鎖。
// readerCount == 0 且 readerWait > 0:表示有寫者在等待讀鎖,阻塞中。
// readerCount == 0 且 readerWait == 0:表示當(dāng)前沒有讀者持有讀鎖,且沒有寫者在等待讀鎖。此時(shí)其他寫者可以嘗試獲取寫鎖。
// 這樣的設(shè)計(jì)是為了在寫者等待讀鎖時(shí),不允許新的讀者加入,以確保寫者獲得更公平的機(jī)會(huì)。

RLock

在這里插入圖片描述

// Happens-before relationships are indicated to the race detector via:
// - Unlock  -> Lock:  readerSem
// - Unlock  -> RLock: readerSem
// - RUnlock -> Lock:  writerSem
//
// happends-before 用于描述時(shí)間發(fā)生的順序,在 這里 (代碼中的注釋)
// Unlock 事件發(fā)生之前(happens-before)的 Lock 事件。
// Unlock 事件發(fā)生之前(happens-before)的 RLock 事件。
// RUnlock 事件發(fā)生之前(happens-before)的 Lock 事件


func (rw *RWMutex) RLock() {
	if race.Enabled {
		_ = rw.w.state
		race.Disable()
	}
	// 它將 readerCount 增加 1。如果結(jié)果小于 0,說明有一個(gè)寫者拿著鎖了, 這邊需要等著
	if rw.readerCount.Add(1) < 0 {
		// A writer is pending, wait for it.
		// 在讀寫鎖的情況下 執(zhí)行鎖的信號(hào)量 
		// 實(shí)際得等待操作, 調(diào)用底層代碼, 等寫者釋放鎖
		runtime_SemacquireRWMutexR(&rw.readerSem, false, 0)
	}
	if race.Enabled {
		race.Enable()
		race.Acquire(unsafe.Pointer(&rw.readerSem))
	}
}

race.Enabled : 競態(tài)檢測, 是go運(yùn)行時(shí)提供的工具, 用于檢測并發(fā)程序中的數(shù)據(jù)競爭問題,
使用 go run -race main.go 可以檢測, 然后輸出報(bào)告。
后面競態(tài)檢測代碼 不說明

RUnlock

在這里插入圖片描述

// RUnlock undoes a single RLock call;
// it does not affect other simultaneous readers.
// It is a run-time error if rw is not locked for reading
// on entry to RUnlock.
func (rw *RWMutex) RUnlock() {
	... // 競態(tài)規(guī)則邏輯
	// readerCount 用于記錄當(dāng)前持有讀鎖的讀者數(shù)量。如果讀者計(jì)數(shù)減為負(fù)數(shù),說明存在寫者正在等待讀鎖釋放
	if r := rw.readerCount.Add(-1); r < 0 {
		// Outlined slow-path to allow the fast-path to be inlined
		rw.rUnlockSlow(r)
	}
	... // 競態(tài)規(guī)則邏輯
}
func (rw *RWMutex) rUnlockSlow(r int32) {
	... // 競態(tài)規(guī)則邏輯
	// A writer is pending.
	// 減少讀者等待計(jì)數(shù)。readerWait 記錄正在等待讀鎖釋放的讀者數(shù)量。如果讀者等待計(jì)數(shù)減為零,
	// 說明最后一個(gè)讀者已經(jīng)釋放了讀鎖,可以喚醒等待的寫者
	if rw.readerWait.Add(-1) == 0 {
		// The last reader unblocks the writer.
		// 釋放寫者的信號(hào)量
		runtime_Semrelease(&rw.writerSem, false, 1)
	}
}

在這里插入圖片描述

func (rw *RWMutex) Lock() {
	... // 競態(tài)規(guī)則邏輯
	// First, resolve competition with other writers.
	// 獲取寫鎖,解決與其他寫者的競爭
	rw.w.Lock()
	// Announce to readers there is a pending writer.
	// 將 readerCount 減去 rwmutexMaxReaders,然后再加上 rwmutexMaxReaders,目的是將 readerCount 設(shè)置為負(fù)數(shù),
	// 表示有一個(gè)寫者正在等待寫鎖。這會(huì)通過 readerWait 記錄下來,并用于通知讀者和寫者。
	// 這邊得  rw.readerCount 是一個(gè)負(fù)數(shù), 在RLock 中有個(gè)判斷 rw.readerCount <0 , 
	// 這一段就是實(shí)現(xiàn)了寫者優(yōu)先, 不管當(dāng)前有沒有讀者拿著讀鎖, 接下來拿鎖的讀鎖, 統(tǒng)統(tǒng)排我后面,不能影響我(寫者), 等我(寫者)處理完了再說
	r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders
	// Wait for active readers.
	// 如果有活躍的讀者,且將 readerWait 增加 r 后不為零,說明有讀者正在等待讀鎖釋放
	if r != 0 && rw.readerWait.Add(r) != 0 {
	// 獲取寫鎖。
	// 它不是馬上就能獲取寫鎖,而是可能會(huì)被阻塞,需要等待寫鎖的釋放
	// 當(dāng)寫者執(zhí)行這個(gè)操作時(shí),如果當(dāng)前沒有其他寫者或讀者持有鎖,那么它會(huì)成功獲取寫鎖,否則它會(huì)被阻塞,直到?jīng)]有其他寫者或讀者持有鎖
		runtime_SemacquireRWMutex(&rw.writerSem, false, 0)
	}
	... // 競態(tài)規(guī)則邏輯
}

Unlock

在這里插入圖片描述

// arrange for another goroutine to RUnlock (Unlock) it.
func (rw *RWMutex) Unlock() {
	... // 競態(tài)規(guī)則邏輯

	// Announce to readers there is no active writer.
	// 將 readerCount 增加 rwmutexMaxReaders,用于通知活躍的讀者,寫者已經(jīng)釋放了寫鎖
	// 我( 寫者)處理完了, 把 rw.readerCount 加回來了, 當(dāng)前寫鎖寫完了, 剛剛我(寫者)拿鎖以后 申請(qǐng)的讀鎖們, 可以喚醒了
	r := rw.readerCount.Add(rwmutexMaxReaders)
	... // 競態(tài)規(guī)則邏輯
	// Unblock blocked readers, if any.
	// 遍歷并逐個(gè)釋放等待的讀者,通過 runtime_Semrelease 信號(hào)量操作通知它們。
	for i := 0; i < int(r); i++ {
		runtime_Semrelease(&rw.readerSem, false, 0)
	}
	// Allow other writers to proceed.
	rw.w.Unlock()
	... // 競態(tài)規(guī)則邏輯
}

go 運(yùn)行時(shí)方法

1、runtime_SemacquireRWMutexR(&rw.readerSem, false, 0):

這個(gè)方法用于獲取讀鎖。
&rw.readerSem 是一個(gè)信號(hào)量,表示等待讀鎖的讀者隊(duì)列。
false 表示不以 LIFO(LastIn, First Out)模式進(jìn)行等待隊(duì)列的管理。 、
0 表示無超時(shí)。

2、runtime_SemacquireRWMutex(&rw.writerSem, false, 0):

這個(gè)方法用于獲取寫鎖。
&rw.writerSem 是一個(gè)信號(hào)量,表示等待寫鎖的寫者隊(duì)列。
false 表示不以 LIFO模式進(jìn)行等待隊(duì)列的管理。
0 表示無超時(shí)。

3、runtime_Semrelease(&rw.writerSem, false, 1):

這個(gè)方法用于釋放寫鎖。
&rw.writerSem 是寫鎖等待隊(duì)列的信號(hào)量。
false 表示不以 LIFO 模式進(jìn)行等待隊(duì)列的管理。
1 表示釋放一個(gè)寫者,通知等待的寫者。

4、runtime_Semrelease(&rw.readerSem, false, 0):

這個(gè)方法用于釋放讀鎖。
&rw.readerSem 是讀鎖等待隊(duì)列的信號(hào)量。
false 表示不以 LIFO 模式進(jìn)行等待隊(duì)列的管理。
0表示釋放一個(gè)讀者,通知等待的讀者

到此這篇關(guān)于go中sync.RWMutex的源碼解讀的文章就介紹到這了,更多相關(guān)go sync.RWMutex內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

您可能感興趣的文章:

相關(guān)文章

  • 解密Golang中Request對(duì)象的操作

    解密Golang中Request對(duì)象的操作

    這篇文章主要和大家深入探討?Golang?中的?Request?對(duì)象,并從多個(gè)方面介紹其功能、結(jié)構(gòu)和使用方法,文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2023-05-05
  • 基于Go和PHP語言實(shí)現(xiàn)爬樓梯算法的思路詳解

    基于Go和PHP語言實(shí)現(xiàn)爬樓梯算法的思路詳解

    這篇文章主要介紹了Go和PHP 實(shí)現(xiàn)爬樓梯算法,本文通過動(dòng)態(tài)規(guī)劃和斐波那契數(shù)列兩種解決思路給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Go Slice擴(kuò)容的這些坑你踩過哪些

    Go Slice擴(kuò)容的這些坑你踩過哪些

    這篇文章主要為大家詳細(xì)介紹了Golang中對(duì)切片Slice的append操作時(shí)會(huì)遇到的踩坑經(jīng)驗(yàn)分享,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-03-03
  • 詳解Go?sync?同步原語

    詳解Go?sync?同步原語

    Go?中不僅有?channel?這種?CSP?同步機(jī)制,還有?sync.Mutex、sync.WaitGroup?等比較原始的同步原語,使用它們,可以更靈活的控制數(shù)據(jù)同步和多協(xié)程并發(fā),這篇文章主要介紹了Go?sync?同步原語,需要的朋友可以參考下
    2023-12-12
  • Go并發(fā)編程之sync.Once使用實(shí)例詳解

    Go并發(fā)編程之sync.Once使用實(shí)例詳解

    sync.Once使用起來很簡單, 下面是一個(gè)簡單的使用案例,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-11-11
  • 執(zhí)行g(shù)o?build報(bào)錯(cuò)go:?go.mod?file?not?found?in?current?directory?or?any?parent?directory

    執(zhí)行g(shù)o?build報(bào)錯(cuò)go:?go.mod?file?not?found?in?current?dir

    本文主要為大家介紹了執(zhí)行g(shù)o build報(bào)錯(cuò)go:?go.mod?file?not?found?in?current?directory?or?any?parent?directory解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • 從Node.js 轉(zhuǎn)到 Go平臺(tái)

    從Node.js 轉(zhuǎn)到 Go平臺(tái)

    回顧過去的一年,我們?cè)诩夹g(shù)棧上的最大改變就是從 Node.js 切換到 Go 。我們的聯(lián)合創(chuàng)始人,Steve Kaliski, 在 Poptip 把 Node.js 切換成了 Go,可惜他沒有學(xué)習(xí)到當(dāng)時(shí)的教訓(xùn)。
    2015-03-03
  • Golang語言如何讀取http.Request中body的內(nèi)容

    Golang語言如何讀取http.Request中body的內(nèi)容

    這篇文章主要介紹了Golang語言如何讀取http.Request中body的內(nèi)容問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 詳解go語言json的使用技巧

    詳解go語言json的使用技巧

    這篇文章主要介紹了詳解go語言json的使用技巧,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 一文告訴你大神是如何學(xué)習(xí)Go語言之make和new

    一文告訴你大神是如何學(xué)習(xí)Go語言之make和new

    當(dāng)我們想要在 Go 語言中初始化一個(gè)結(jié)構(gòu)時(shí),其實(shí)會(huì)使用到兩個(gè)完全不同的關(guān)鍵字,也就是 make 和 new,同時(shí)出現(xiàn)兩個(gè)用于『初始化』的關(guān)鍵字對(duì)于初學(xué)者來說可能會(huì)感到非常困惑,不過它們兩者有著卻完全不同的作用,本文就和大家詳細(xì)講講
    2023-02-02

最新評(píng)論