go sync包(四) 讀寫鎖(二)

讀寫鎖 RWMutex

寫鎖

加鎖

RWMetex 的寫鎖復用了 Mutex

// Lock locks rw for writing.
// If the lock is already locked for reading or writing,
// Lock blocks until the lock is available.
func (rw *RWMutex) Lock() {if race.Enabled {_ = rw.w.staterace.Disable()}// First, resolve competition with other writers.// writer加鎖rw.w.Lock()// Announce to readers there is a pending writer.// 反轉 readerCount,告訴 reader 有writer競爭鎖// Add(-rwmutexMaxReaders) 將 readerCount 置為負數,表示當前有 writer 競爭鎖r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders// Wait for active readers.// 當前有 reader 持有鎖,writer 等待if r != 0 && rw.readerWait.Add(r) != 0 {runtime_SemacquireRWMutex(&rw.writerSem, false, 0)}if race.Enabled {race.Enable()race.Acquire(unsafe.Pointer(&rw.readerSem))race.Acquire(unsafe.Pointer(&rw.writerSem))}
}
解鎖

解鎖也是復用的 Mutex,區別在于解鎖的時候會喚醒所有阻塞的 reader

// Unlock unlocks rw for writing. It is a run-time error if rw is
// not locked for writing on entry to Unlock.
//
// As with Mutexes, a locked RWMutex is not associated with a particular
// goroutine. One goroutine may RLock (Lock) a RWMutex and then
// arrange for another goroutine to RUnlock (Unlock) it.
func (rw *RWMutex) Unlock() {if race.Enabled {_ = rw.w.staterace.Release(unsafe.Pointer(&rw.readerSem))race.Disable()}// Announce to readers there is no active writer.// 反轉 readerCount,告訴 reader 沒有 writer 競爭鎖r := rw.readerCount.Add(rwmutexMaxReaders)if r >= rwmutexMaxReaders {race.Enable()fatal("sync: Unlock of unlocked RWMutex")}// Unblock blocked readers, if any.// 喚醒所有阻塞的 readerfor i := 0; i < int(r); i++ {runtime_Semrelease(&rw.readerSem, false, 0)}// Allow other writers to proceed.// writer 解鎖rw.w.Unlock()if race.Enabled {race.Enable()}
}

讀鎖

加鎖
// RLock locks rw for reading.
//
// It should not be used for recursive read locking; a blocked Lock
// call excludes new readers from acquiring the lock. See the
// documentation on the RWMutex type.
func (rw *RWMutex) RLock() {if race.Enabled {_ = rw.w.staterace.Disable()}// writer 加鎖時,readerCount 是負數// 寫鎖優先級比讀鎖高,reader 休眠// 如果 reader+1 > 0, 當前加了讀鎖if rw.readerCount.Add(1) < 0 {// A writer is pending, wait for it.runtime_SemacquireRWMutexR(&rw.readerSem, false, 0)}if race.Enabled {race.Enable()race.Acquire(unsafe.Pointer(&rw.readerSem))}
}
解鎖
// 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() {if race.Enabled {_ = rw.w.staterace.ReleaseMerge(unsafe.Pointer(&rw.writerSem))race.Disable()}// 有等待的 writerif r := rw.readerCount.Add(-1); r < 0 {// Outlined slow-path to allow the fast-path to be inlinedrw.rUnlockSlow(r)}if race.Enabled {race.Enable()}
}func (rw *RWMutex) rUnlockSlow(r int32) {if r+1 == 0 || r+1 == -rwmutexMaxReaders {race.Enable()fatal("sync: RUnlock of unlocked RWMutex")}// A writer is pending.// 讀鎖全部解鎖完畢,喚醒 writerif rw.readerWait.Add(-1) == 0 {// The last reader unblocks the writer.runtime_Semrelease(&rw.writerSem, false, 1)}
}

小結

  • sync.RWMutex 復用 sync.Mutex
  • 寫鎖:
    • 加鎖時 writer 反轉 readerCount 置為負數,如果當前有 reader 正在執行, readerCount 賦值給 readerWait,writer 休眠。
    • 解鎖時 writer 反轉 readerCount 置為正常,并喚醒所有阻塞的 reader。
  • 讀鎖:
    • 加鎖時 readerCount + 1,如果 readerCount < 0,reader 阻塞。
    • 解鎖時 readerCount - 1,如果 readerCount < 0,readerWait - 1,當 readerWait == 0 時,喚醒 writer。

sync.RWMutex 復用 sync.Mutex

  • 調用 sync.RWMutex.Lock 嘗試獲取寫鎖時;
  • 每次 sync.RWMutex.RUnlock 都會將 readerCount 其減一,當它歸零時該 Goroutine 會獲得寫鎖;
  • 將 readerCount 減少 rwmutexMaxReaders 個數以阻塞后續的讀操作;

調用 sync.RWMutex.Unlock 釋放寫鎖時,會先通知所有的讀操作,然后才會釋放持有的互斥鎖;

讀寫互斥鎖在互斥鎖之上提供了額外的更細粒度的控制,能夠在讀操作遠遠多于寫操作時提升性能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/36898.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/36898.shtml
英文地址,請注明出處:http://en.pswp.cn/web/36898.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

安全與發展并重:實施等保,促進企業可持續增長的邏輯

在數字經濟時代&#xff0c;信息安全不僅是企業穩健運營的基石&#xff0c;也是推動可持續發展的重要保障。網絡安全等級保護&#xff08;簡稱“等保”&#xff09;體系&#xff0c;作為國家層面設立的信息安全保障框架&#xff0c;其核心在于平衡安全與發展的關系&#xff0c;…

Java中如何進行分布式系統設計?

Java中如何進行分布式系統設計&#xff1f; 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01;今天&#xff0c;我們來討論如何在Java中進行分布式系統設計。分布式…

什么是 Python 包管理器?怎么安裝?

Python 包管理器是一個用于安裝、升級、卸載和管理 Python 包的工具。Python 的包&#xff08;也稱為模塊或庫&#xff09;是預編寫的 Python 代碼&#xff0c;用于執行各種任務&#xff0c;如數據處理、網頁開發、科學計算等。Python 包管理器使得這些包的管理變得簡單和高效。…

Android Gradle開發與應用 (第一部分):入門Gradle基礎

Gradle 是一個開源的構建自動化工具&#xff0c;廣泛用于Android項目的構建和管理。本文將介紹Gradle的基礎知識&#xff0c;幫助開發者更好地理解和使用Gradle進行Android應用開發。 目錄 什么是GradleGradle的基本概念配置Gradle環境Gradle構建腳本結構常用Gradle命令多項目…

計算Dice損失的函數

計算Dice損失的函數 def Dice_loss(inputs, target, beta1, smooth 1e-5):n,c, h, w inputs.size() #nt,ht, wt, ct target.size() #nt,if h ! ht and w ! wt:inputs F.interpolate(inputs, size(ht, wt), mode"bilinear", align_cornersTrue)temp_inputs t…

LLaMA-Factory安裝

安裝代碼 https://github.com/echonoshy/cgft-llm/blob/master/llama-factory/README.md https://github.com/hiyouga/LLaMA-Factory/tree/mainLLaMA-Factoryhttps://github.com/hiyouga/LLaMA-Factory/tree/main 【大模型微調】- 使用Llama Factory實現中文llama3微調_嗶哩…

TIA博途WinCC通過VB腳本從 Excel中讀取數據的具體方法介紹

TIA博途WinCC通過VB腳本從 Excel中讀取數據的具體方法介紹 添加 一個PLC,設置PLC的IP地址,如下圖所示, 添加全局DB塊,新建幾個變量,如下圖所示, 在數據塊中添加了 tag1 …… tag6 ,共 6 個浮點數類型的變量,用來接收通過 WinCC 從 Excel 文件中讀取的數據。 添加 HMI…

Holt-Winters季節性方法

Holt-Winters季節性方法是時間序列預測中一種常用的方法&#xff0c;它通過三次指數平滑處理數據中的趨勢和季節性成分。下面將詳細解釋該方法的原理和步驟&#xff1a; 1. 數據準備 數據收集與整理&#xff1a;首先需要收集和整理時間序列數據&#xff0c;確保數據的準確性和…

什么是pip命令

pip 是 Python 的包管理器&#xff0c;用于安裝和管理 Python 包&#xff08;也稱為模塊或庫&#xff09;。Python 包是預編寫的 Python 代碼&#xff0c;用于執行特定任務&#xff0c;如數據處理、網頁開發、科學計算等。通過使用 pip&#xff0c;您可以輕松地安裝、升級或卸載…

iOS 語言基礎初探 Xcode 工具

iOS&#xff08;iPhone 操作系統&#xff09;是由蘋果公司開發的移動操作系統&#xff0c;運行在iPhone、iPad和iPod Touch等設備上。蘋果官方推薦使用Objective-C和Swift這兩種編程語言來開發iOS應用程序。 Objective-C是一種面向對象的編程語言&#xff0c;也是iOS開發的主要…

gdb-dashboard:用Python重塑GDB調試體驗

gdb-dashboard&#xff1b;一目了然的GDB調試&#xff0c;盡在掌控之中- 精選真開源&#xff0c;釋放新價值。 概覽 gdb-dashboard是一個用Python編寫的模塊化視覺界面&#xff0c;為GNU Debugger&#xff08;GDB&#xff09;提供了一個現代化的工作空間。它通過集成多個面板和…

數據平臺發展史-從數據倉庫數據湖到數據湖倉

做數據的同學經常聽到一些數據相關的術語&#xff0c;常見的包括數據倉庫&#xff0c;邏輯數據倉庫&#xff0c;數據湖&#xff0c;數據湖倉/湖倉一體&#xff0c;數據網格 data mesh,數據編織 data fabric等. 筆者在這里回顧了下數據平臺的發展史&#xff0c;也介紹和對比了下…

【QT】按鈕類控件 顯示類控件

目錄 按鈕類控件 Push Button 設置按鈕圖標 按鈕設置快捷鍵 設置鼠標點擊按鈕重復觸發 Radio Button 單選框分組 Check Box 顯示類控件 Label 常用屬性 設置文本格式 給Label設置圖片 Label標簽設置邊框 設置文本對齊方式 設置文本自動換行 設置文本縮進 設置…

Python入門-基本數據類型-字符串類型及其操作

字符串類型存儲的數據是字符串&#xff0c;字符串是一個由字符構成的序列。Python字符串是不可變的 不支持動態修改。本節將對字符串進行簡單介紹&#xff0c;包括字符串的定義方式、格式化、索引、切片 拼接、重復和成員歸屬等。 1.字符串的定義方式 1.1單行字符串 單行字符…

《概率論與數理統計》期末筆記_下

目錄 第4章 隨機變量的數字特征 4.1 數學期望 4.2 方差 4.3 常見分布的期望與方差 4.4 協方差與相關系教 第5章 大數定律和中心極限定理 5.1 大數定律 5.2 中心極限定理 第6章 樣本與抽樣分布 6.1 數理統汁的基本概念 6.2 抽樣分布 6.2.1 卡方分布 6.2.2 t分布 6.…

高效利用iCloud的指南

高效利用iCloud的指南可以幫助你充分利用Apple提供的云服務&#xff0c;以下是一些關鍵的步驟和建議&#xff1a; 了解iCloud的基本功能 iCloud是Apple提供的云服務&#xff0c;可以安全地存儲你的個人信息&#xff0c;包括照片、文件、備忘錄、日歷、聯系人等。通過iCloud&…

JavaScript(4)——數組,常量

let和var的區別 var可以先使用再聲明var聲明過的變量可以重復聲明 數組 聲明語法&#xff1a; let 數組名 [數據1&#xff0c;數據2&#xff0c;數據3,...] 數組是按順序保存&#xff0c;所以每個數據都有自己的編號計算機中的編號從0開始編號也叫索引或下標 數組可以存儲任…

java基于ssm+jsp 高校畢業生就業滿意度調查統計系統

1用戶前臺功能模塊 高校畢業生就業滿意度調查統計系統&#xff0c;在高校畢業生就業滿意度調查統計系統可以查看首頁、問卷、就業咨詢、試卷列表、新聞資訊、留言反饋、我的、跳轉到后臺等內容&#xff0c;如圖1所示。 圖1系統首頁界面圖 用戶登錄、用戶注冊&#xff0c;通過…

LabVIEW代碼性能優化

優化LabVIEW代碼以提高軟件性能是確保系統高效運行的關鍵。通過分析代碼結構、數據管理、并行處理、內存使用和硬件資源的有效利用&#xff0c;我們可以從多個角度提升LabVIEW程序的執行速度和穩定性。 代碼結構優化 模塊化編程 將復雜的程序分解成多個子VI&#xff0c;每個子V…

Linux-進程間通信(IPC)

進程間通信&#xff08;IPC&#xff09;介紹 進程間通信&#xff08;IPC&#xff0c;InterProcess Communication&#xff09;是指在不同的進程之間傳播或交換信息。IPC 的方式包括管道&#xff08;無名管道和命名管道&#xff09;、消息隊列、信號量、共享內存、Socket、Stre…