Golang RWMutex 原始碼閱讀

2021-09-21 01:42:22 字數 2032 閱讀 7584

資料結構

type rwmutex struct
w:互斥鎖,多個寫 goroutine之間競爭

writersem: 加寫鎖的訊號量

readersem: 加讀鎖的訊號量

readercount: 需要加讀鎖的數(已經獲取到的+待獲取的)

readerwait: 已經獲取到讀鎖數

寫鎖lock

func (rw *rwmutex) lock() 

...}

rw 是乙個mutex,主要是用來多個協程之間互斥;

readercount 執行addint32之後會是乙個特別大的負值

readerwait就等於加寫鎖一刻的readercount 數

如果atomic.addint32(&rw.readerwait, r) != 0 就說明有已經獲取到讀鎖的協程,等待rw.writersem 訊號量釋放

(通過後面的讀鎖釋放可以看到,writersem 訊號量釋放的時候,readerwait == 0)

寫鎖 unlock

func (rw *rwmutex) unlock() 

// unblock blocked readers, if any.

for i := 0; i < int(r); i++

// allow other writers to proceed.

rw.w.unlock()

...}

加寫鎖的時候,將readercount 減去乙個特別大的數rwmutexmaxreaders,所以釋放寫鎖,先還原readercount

因為加寫鎖成功的情況只有readerwait == 0

如果r大於0,說明有需要 r 個需要加讀鎖的協程,就需要 readersem 訊號量release r次

最後釋放w mutex的鎖

讀鎖rlock

func (rw *rwmutex) rlock() 

}

只要readercount 小於0 ,就認為有協程加完寫鎖,此時等待readersem 訊號量

讀鎖 runlock

func (rw *rwmutex) runlock() 

// a writer is pending.

if atomic.addint32(&rw.readerwait, -1) == 0

} ...

}

如果readercount 小於0,就說明有寫鎖在等待

將readerwait 數量減1 當readerwait == 0 的時候,此時沒有獲取到讀鎖的協程了,釋放writersem 訊號量

最大讀鎖數 rwmutexmaxreaders

readercount 應當小於 rwmutexmaxreaders,否則加寫鎖時 atomic.addint32(&rw.readercount, -rwmutexmaxreaders) 直接就》=0了,那讀鎖就認為沒有需要加寫鎖的goroutine

讀寫鎖的順序

從上面**可以看出,當乙個寫鎖釋放之後,如果同時有需要加讀鎖和寫鎖的goroutine,優先加讀鎖,因為先釋放的readersem,後釋放的w(mutex),當w unlock之後,之後的需要加讀鎖的goroutine又會pending。

不要遞迴加讀鎖

假如出現遞迴加讀鎖的情況,從上面**分析中可以看出來,當有乙個goroutine 需要加寫鎖之後,後面的加讀鎖操作都會pending,程式會block

在遞迴呼叫中,新的讀鎖會pending,之前加完讀鎖的不能釋放,而寫鎖也會pending。

func f(n int) int 

fmt.println("rlock")

m.rlock()

defer func() ()

time.sleep(100 * time.millisecond)

return f(n-1) + n

}func main() ()

f(4)

<-done

}

AbstractCollection原始碼分析

abstractcollection抽象類提供了collection的骨架實現,collection分析請看 這裡直接看它的 是如何實現的.public abstract iterator iterator 該方法沒有實現.public abstract int size 該方法沒有實現.publi...

ThreadPoolExecutor原始碼閱讀

執行緒池解決兩個問題 一是復用執行緒,減少建立銷毀執行緒帶來系統開銷 二是限定系統資源使用邊界,避免大量執行緒消耗盡系統記憶體 適用於互不依賴,執行時間短,不需要對執行緒控制操作的執行緒 新增任務時,1.若執行緒數量小於corepoolsize,則新增執行緒執行任務 2.若執行緒數量大於等於core...

OrangePi One Android 原始碼編譯

一 系統環境搭建參照 二 lichee原始碼編譯 1.檢視help build.sh h2.配置核心 cd linux 3.4 make arch arm menuconfig 進入配置頁面,上下移動列表,空格是選擇列表,左右移動選擇退出選項 3.首次編譯執行清除 在 lichee linux3.4...