天天看點

名不符實的讀寫鎖

有一種單一寫線程,多個讀線程并發的場景,比如測量資料的讀取與更新,消費者會比較多,生産者隻有一個。以下圖為例:

名不符實的讀寫鎖

左側是一種經典的解法,對資料整個操作加鎖。為了一個寫資料線程,于将所有讀線程也進行加鎖顯然有點浪費了。于是提出讀寫鎖(Reader/Writer Lock), 即使是使用了讀寫鎖,其本質也是一樣的,而且在POSIX下的pthread它的内部實作是基于mutex,是以它的開銷更大。如果沒有很重的讀操作來抵消它引入的開銷,反而會引起性能的下降。已經多組測試資料來證明這一點。我自己也做了驗證,得到資料如下 (單個寫線程,20個讀線程),使用讀寫鎖反而比使用mutex要慢。詳細可以參考兩個連結:

這一類問題,在資料庫領域有一類解決方案,被稱為Multiversion Concurrency Control, 其目的是以增加資料複本保證使用者每一次使用都可以用到完整的資料,但不一定是最新的資料。再簡化一點,其思想就是建立一個資料複本,專門用于寫。當資料完全準備好後,切換出來供其它線程讀。原本的資料就轉為下一次寫使用。 即上圖中右側所示的方式。

以這個方案,隻要對Writing/Reading的處理加鎖就可以了。這樣測試出來的性能開銷因為加鎖的處理時間極短,較一般Mutex和Reader/Writer Lock都要好 (最後一個算法):

名不符實的讀寫鎖

詳細的不展開了。另外有一些更為通用的方式,包括平衡讀寫的吞吐的問題,稱為Spin Buffer,有興趣可以進一步研究。

附源代碼如下供參考:

使用如下方式編譯測試:

有空再寫篇關于多線程算法選擇的文檔!