1. 程式人生 > >Linux RCU鎖簡析

Linux RCU鎖簡析

最近遇到一個問題,大壓力測試下咬狗了,定位出來跟RCU相關,還是先簡單的捋一捋RCU,也好看看後面能否對RCU做些特定場景下的優化。

網上RCU相關的技術部落格比較多,先列幾個可供參考的:

MagicBoy201寫的《再談Linux核心中的RCU機制》http://blog.chinaunix.net/uid-23769728-id-3080134.html

這篇部落格寫的比較巨集觀一些。

《linux核心 RCU機制詳解》 http://blog.csdn.net/xabc3000/article/details/15335131

原文沒找到,這篇博文看看前段就好,了就下什麼是RCU和寬限期。

<深入淺出> linux核心 RCU (一)經典RCU

》http://blog.csdn.net/chenyu105/article/details/7910269

<深入淺出> linux核心 RCU (二)分級RCU》http://blog.csdn.net/chenyu105/article/details/23104221

這兩篇博文 經典RCU寫的很不錯,把經典RCU的邏輯實現都寫出來了。

RCU (Read-Copy Update)是一種同步機制,是對讀寫鎖的優化。

先簡單瞭解一下讀寫鎖,rwlock可以多個執行緒同時佔用讀模式的讀寫鎖,但是隻能一個執行緒佔用寫模式的讀寫鎖,即

(1)當有人拿到寫鎖的時候,任何人都不能再拿到讀鎖或寫鎖

(2)當有人拿到讀鎖的時候,其他人也可以拿到讀鎖,但不能有人拿到寫鎖去修改臨界區

(3)已經加了讀鎖時,如有人嘗試拿寫鎖,需要儘快得到滿足,避免寫鎖飢餓

RCU的行為方式

(1)隨時可以拿到讀鎖,即對臨界區的讀操作隨時都可以得到滿足

(2)某一時刻只能有一個人拿到寫鎖,多個寫鎖需要互斥,寫的動作包括 拷貝--修改--寬限視窗到期後刪除原值

(3)臨界區的原始值為m1,如會有人拿到寫鎖修改了臨界區為m2,則在寫鎖修改臨界區之後拿到的讀鎖獲取的臨界區的值為m2,之前獲取的為m1,這通過原子操作保證

對比發現RCU讀操作隨時都會得到滿足,但寫鎖之後的寫操作所耗費的系統資源就相對比較多了,並且只有在寬限期之後刪除原資源。

RCU寬限期:

 圖中每行代表一個執行緒,最下面的一行是刪除執行緒,當它執行完刪除操作後,執行緒進入了寬限期。寬限期的意義是,在一個刪除動作發生後,它必須等待所有在寬限期開始前已經開始的讀執行緒結束,才可以進行銷燬操作。這樣做的原因是這些執行緒有可能讀到了要刪除的元素。圖中的寬限期必須等待1和2結束;而讀執行緒5在寬限期開始前已經結束,不需要考慮;而3,4,6也不需要考慮,因為在寬限期開始後的執行緒不可能讀到已刪除的元素。


寬限期的描述來源於《linux核心 RCU機制詳解》 http://blog.csdn.net/xabc3000/article/details/15335131

寬限期的定義引來幾個問題(後文稱RCU問題)

(1)寬限期的開始即預示著RCU監測的開始,需要監測寬限期開始之前的執行緒是否結束

(2)寬限期是否在呼叫call_rcu之後馬上開始?答案是否定的,同一時刻只有一個寬限期,在某個寬限期內新加入的所有call_rcu回撥會合併為一個寬限期,在此寬限期到期後

一起得到呼叫,即下圖中右邊所示


(3)如何判斷一個寬限期到期

經典(classic)RCU讀鎖就是關核心搶佔,讀鎖釋放時再開核心搶佔,因此判斷執行在某CPU上執行緒是否有釋放讀鎖的一個間接方式就是觀察這個CPU上是否發生了排程(該CPU一直idle狀態需額外處理),這種判斷方式簡單而暴力,在非搶佔核心中實時性肯定不是很好,但總體的開銷要比釋放讀鎖後再發一個直接的“通知”要小。因此開啟一個寬限視窗後,如果監測到所有的CPU在監測點之後都發生過一次排程則就可以認為寬限期到期了,就可以釋放原始資料了,太簡單暴力了,可能某些CPU上執行的執行緒跟這個寬限視窗所服務的RCU一點關係都沒有,可RCU就是做的這麼暴力,這也是一些應用場景需要解決的問題,通過修改RCU的監測機制是能做到不這麼暴力的。

RCU要實現的邏輯是:

(1)使用者註冊RCU回撥(call_rcu)

(2)將新註冊的RCU回撥放到一個緩衝佇列(連結串列)中,或正式佇列中為空時直接放到一個正式佇列中

(3)在時鐘中斷---軟中斷中判斷如沒有一個有效的寬限視窗存在,而使用者有發起“開窗”請求(上述連結串列非空),則開啟一個寬限視窗,開始監測系統中所有的CPU是否有排程(通過點陣圖、per cpu變數)

(4)在時鐘中斷---軟中斷中監測到寬限期到後(所有CPU都發生了排程),則執行RCU回撥/啟用RCU軟中斷

(5)為解決RCU問題2,CPU過多時操作點陣圖引起的cache line問題、競爭問題,軟中斷超長等等問題,RCU具體實現的時候應用了一些比較巧妙的方式,來提高RCU的效能

(6)以上行為(1);(2)(3)(4)周而復始。

RCU一直在優化,2.6.25 ,2.6.34,3.10,4.1,不同版本的RCU實現已經有比較大的區別了,早起版本理解起來更直觀一些,

有興趣的話可以上http://lxr.oss.org.cn/快速瀏覽一下早起的程式碼。

後面計劃再結合3.10和4.1核心賞析一下RCU的實現,體味一下RCU作者的匠心。