最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang RWMutex讀寫鎖實(shí)現(xiàn)讀共享寫?yīng)氄嫉墓δ苁纠?/h1>
 更新時(shí)間:2023年09月27日 09:22:57   作者:lincoln_hlf1  
在 Go 里除了互斥鎖外,還有讀寫鎖 RWMutex,它主要用來實(shí)現(xiàn)讀共享,寫?yīng)氄嫉墓δ?今天我們也順便分析下讀寫鎖,加深對(duì) Go 鎖的理解

引言

在上一篇文章 golang 重要知識(shí):mutex 里我們介紹了互斥鎖 mutex 的相關(guān)原理實(shí)現(xiàn)。而且在 Go 里除了互斥鎖外,還有讀寫鎖 RWMutex,它主要用來實(shí)現(xiàn)讀共享,寫?yīng)氄嫉墓δ?。今天我們也順便分析下讀寫鎖,加深對(duì) Go 鎖的理解

讀寫鎖的實(shí)現(xiàn)原理

所謂的讀寫鎖,其實(shí)就是針對(duì)下面的兩種場(chǎng)景,對(duì) Goroutine 之間的同步互斥進(jìn)行控制:

  • 多個(gè) goroutine 一起占有讀鎖,互不影響,可以繼續(xù)自己后面的邏輯代碼。
  • 寫鎖正在占有著,則后面的 goroutine 無論是要進(jìn)行讀鎖占有,還是寫鎖占有,都將會(huì)被阻塞等待,直到當(dāng)前的寫鎖釋放。

弄清楚上面的場(chǎng)景需求后,實(shí)現(xiàn)就簡(jiǎn)單多了,關(guān)鍵就在于判斷當(dāng)前是否處于寫鎖狀態(tài)即可,畢竟需要有阻塞等待的動(dòng)作。

按照常規(guī)思路,我們一般會(huì)采用一個(gè)標(biāo)識(shí)位來維護(hù)這個(gè)狀態(tài)。然而,Go 官方卻連這一步都省了。

利用了一個(gè)本來就得維護(hù)的讀鎖數(shù)量,在進(jìn)行寫鎖占有時(shí),使它變?yōu)樨?fù)數(shù)。

后面有新進(jìn)來的讀寫操作,只需要判斷該值是否正負(fù)即可,負(fù)數(shù)則代表當(dāng)前正在進(jìn)行寫鎖占有,需要阻塞等待。

而在寫鎖占有結(jié)束后,該值又會(huì)恢復(fù)為正數(shù),又可以進(jìn)行新的讀寫操作了。

RWMutex 源碼分析

接下來,我們到 src/runtime/rwmutex.go里具體分析下 RWMutex 的代碼結(jié)構(gòu)。

// rwmutex 是一個(gè)讀寫互斥的鎖
// 將允許多個(gè) goroutine 持有讀鎖,但寫鎖只會(huì)有一個(gè)持有
// rwmutex 使用了 sync.RWMutex 來輔助寫鎖互斥
type rwmutex struct {
rLock      mutex    // 用于保護(hù)設(shè)置 readers, readerPass, writer
readers    muintptr // 休眠等待的 goroutine 讀鎖隊(duì)列,等到寫鎖占有結(jié)束后將對(duì)應(yīng)被喚起。
readerPass uint32   // 讀鎖隊(duì)列需要跳過的 goroutine 數(shù)量,當(dāng)在寫鎖結(jié)束后會(huì)喚起讀鎖隊(duì)列里的 goroutine,但有的可能已不在隊(duì)列里了,這部分需跳過。
wLock  mutex    // 用于 writer 之間的互斥鎖
writer muintptr // 等待讀完成的 writer
readerCount uint32 // 正在執(zhí)行讀操作的 goroutine數(shù)量
readerWait  uint32 // 等待讀鎖釋放的數(shù)量。當(dāng)寫鎖占有后,前面還有部分讀鎖在繼續(xù)著,需要等它們釋放才能繼續(xù)進(jìn)行。
}

RWMutex 的 Lock() 分析

func (rw *rwmutex) Lock() {
    // 用于多個(gè)寫鎖之間的的競(jìng)爭(zhēng)
    lock(&rw.wLock)
    m := getg().m
    // 將讀鎖數(shù)量 readerCount 置為負(fù)數(shù),用于判斷當(dāng)前是否處于寫鎖占有狀態(tài),
    // rw.readerCount < 0 則表示當(dāng)前正在進(jìn)行寫鎖占有.
    r := int32(atomic.Xadd(&rw.readerCount, -rwmutexMaxReaders)) + rwmutexMaxReaders
    // 前面還有讀鎖在進(jìn)行著,需要等待釋放完才能繼續(xù)
    lock(&rw.rLock)
    if r != 0 && atomic.Xadd(&rw.readerWait, r) != 0 {
        systemstack(func() {
            rw.writer.set(m)
            unlock(&rw.rLock)
            notesleep(&m.park)
            noteclear(&m.park)
        })
    } else {
        unlock(&rw.rLock)
    }
}

RWMutex 的 RLock() 分析

func (rw *rwmutex) Rlock() {
    acquirem()
    if int32(atomic.Xadd(&rw.readerCount, 1)) < 0 {
        // 讀鎖數(shù)量 readerCount + 1 后小于 0,表示當(dāng)前正被寫鎖占有,
        // 等待寫鎖釋放
        systemstack(func() {
            lock(&rw.rLock)
            if rw.readerPass > 0 {
                rw.readerPass -= 1
                unlock(&rw.rLock)
            } else {
                // 等待寫鎖喚起
                m := getg().m
                m.schedlink = rw.readers
                rw.readers.set(m)
                unlock(&rw.rLock)
                notesleep(&m.park)
                noteclear(&m.park)
            }
        })
    }
}

RWMutex 的 Unlock() 分析

func (rw *rwmutex) Unlock() {
    // 將原來被寫鎖置為負(fù)數(shù)的 readerCount 重新恢復(fù)回來.
    r := int32(atomic.Xadd(&rw.readerCount, rwmutexMaxReaders))
    if r >= rwmutexMaxReaders {
        throw("unlock of unlocked rwmutex")
    }
    // 喚起之前等待的讀鎖.
    lock(&rw.rLock)
    for rw.readers.ptr() != nil {
        reader := rw.readers.ptr()
        rw.readers = reader.schedlink
        reader.schedlink.set(nil)
        notewakeup(&reader.park)
        r -= 1
    }
    // 如果 r > 0, 說明讀鎖隊(duì)列里有的 goroutine 已不在隊(duì)列里了,這部分需跳過
    rw.readerPass += uint32(r)
    unlock(&rw.rLock)
    // 解除寫鎖
    unlock(&rw.wLock)
}

RWMutex 的 RUnlock() 分析

func (rw *rwmutex) RUnlock() {
    // 如果釋放后,readerCount < 0,表示當(dāng)前寫鎖正在占有
    if r := int32(atomic.Xadd(&rw.readerCount, -1)); r < 0 {
        if r+1 == 0 || r+1 == -rwmutexMaxReaders {
            throw("runlock of unlocked rwmutex")
        }
        // readerWait == 0,表示前面的讀鎖都釋放完了,
        // 需要喚起寫鎖
        if atomic.Xadd(&rw.readerWait, -1) == 0 {
            // The last reader unblocks the writer.
            lock(&rw.rLock)
            w := rw.writer.ptr()
            if w != nil {
                notewakeup(&w.park)
            }
            unlock(&rw.rLock)
        }
    }
    releasem(getg().m)
}

總結(jié)

RWMutex 通過 readerCount 的正負(fù)來判斷當(dāng)前是處于讀鎖占有還是寫鎖占有。

在處于寫鎖占有狀態(tài)后,會(huì)將此時(shí)的 readerCount 賦值給 readerWait,表示要等前面 readerWait 個(gè)讀鎖釋放完才算完整的占有寫鎖,才能進(jìn)行后面的獨(dú)占操作。

讀鎖釋放的時(shí)候, 會(huì)對(duì) readerWait 對(duì)應(yīng)減一,直到為 0 值,就可以喚起寫鎖了。

并且在寫鎖占有后,即時(shí)有新的讀操作加進(jìn)來, 也不會(huì)影響到 readerWait 值了,只會(huì)影響總的讀鎖數(shù)目:readerCount。

以上就是golang RWMutex讀寫鎖實(shí)現(xiàn)讀共享寫?yīng)氄嫉墓δ苁纠脑敿?xì)內(nèi)容,更多關(guān)于golang RWMutex讀寫鎖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語言使用sqlx操作數(shù)據(jù)庫的示例詳解

    Go語言使用sqlx操作數(shù)據(jù)庫的示例詳解

    sqlx?是?Go?語言中一個(gè)流行的第三方包,它提供了對(duì)?Go?標(biāo)準(zhǔn)庫?database/sql?的擴(kuò)展,本文重點(diǎn)講解?sqlx?在?database/sql?基礎(chǔ)上擴(kuò)展的功能,希望對(duì)大家有所幫助
    2023-06-06
  • Go語言開發(fā)編程規(guī)范命令風(fēng)格代碼格式

    Go語言開發(fā)編程規(guī)范命令風(fēng)格代碼格式

    這篇文章主要為大家介紹了Go語言開發(fā)編程規(guī)范命令風(fēng)格代碼格式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • go語言goto語句跳轉(zhuǎn)到指定的標(biāo)簽實(shí)現(xiàn)方法

    go語言goto語句跳轉(zhuǎn)到指定的標(biāo)簽實(shí)現(xiàn)方法

    這篇文章主要介紹了go語言goto語句跳轉(zhuǎn)到指定的標(biāo)簽實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Go實(shí)現(xiàn)SSE消息推送的項(xiàng)目實(shí)戰(zhàn)

    Go實(shí)現(xiàn)SSE消息推送的項(xiàng)目實(shí)戰(zhàn)

    本文主要介紹了Go實(shí)現(xiàn)SSE消息推送的項(xiàng)目實(shí)戰(zhàn),結(jié)合JavaScript前端集成,構(gòu)建實(shí)時(shí)數(shù)據(jù)推送系統(tǒng),文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-05-05
  • Golang交叉編譯之跨平臺(tái)編譯使用詳解

    Golang交叉編譯之跨平臺(tái)編譯使用詳解

    這篇文章主要為大家介紹了Golang交叉編譯之跨平臺(tái)編譯使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • MacOS中 VSCode 安裝 GO 插件失敗問題的快速解決方法

    MacOS中 VSCode 安裝 GO 插件失敗問題的快速解決方法

    這篇文章主要介紹了MacOS中 VSCode 安裝 GO 插件失敗問題的快速解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Go實(shí)現(xiàn)跨平臺(tái)的藍(lán)牙聊天室示例詳解

    Go實(shí)現(xiàn)跨平臺(tái)的藍(lán)牙聊天室示例詳解

    這篇文章主要為大家介紹了Go實(shí)現(xiàn)跨平臺(tái)的藍(lán)牙聊天室示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • go-cqhttp智能聊天功能的實(shí)現(xiàn)

    go-cqhttp智能聊天功能的實(shí)現(xiàn)

    這篇文章主要介紹了go-cqhttp智能聊天功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • 詳解Go語言中的數(shù)據(jù)類型及類型轉(zhuǎn)換

    詳解Go語言中的數(shù)據(jù)類型及類型轉(zhuǎn)換

    這篇文章主要為大家介紹了Go語言中常見的幾種數(shù)據(jù)類型,以及他們之間的轉(zhuǎn)換方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-04-04
  • 詳解Go中Map類型和Slice類型的傳遞

    詳解Go中Map類型和Slice類型的傳遞

    這篇文章主要為大家詳細(xì)介紹了Go中Map類型和Slice類型的傳遞,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11

最新評(píng)論

神农架林区| 奉化市| 德江县| 扎兰屯市| 治县。| 卢龙县| 台江县| 汝阳县| 孙吴县| 孝感市| 寻甸| 乐至县| 临洮县| 永康市| 曲麻莱县| 达孜县| 吴忠市| 广西| 温宿县| 靖州| 织金县| 专栏| 昂仁县| 西和县| 内江市| 彭州市| 谷城县| 台北市| 乌什县| 黔西| 元阳县| 分宜县| 阿拉善右旗| 河南省| 梁山县| 濉溪县| 崇礼县| 乐陵市| 宝坻区| 息烽县| 浑源县|