資料結構
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...