linux 內核的另一個自旋鎖 - 讀寫鎖


除spinlock外,linux 內核還有一個自旋鎖,名為arch_rwlock_t。它的頭文件是qrwlock.h,包含在spinlock.h,頭文件中對它全稱為"Queue read/write lock"。這個鎖只使用了兩個成員變量就實現了讀寫鎖。一個spinlock,以及一個整形鎖變量。而spinlock就是這個Queue。

鎖的原理是,當沒有寫意願或寫鎖使用時,任意讀鎖可以並發。當有寫意願或寫鎖使用時,一切的讀鎖和寫鎖都必須進行排隊。

arch_rwlock_t的鎖變量雖然只是一個整形,但是卻是一個壓縮的復合數據。它包含了讀鎖,寫鎖。

讀鎖,為鎖變量的高24位。只要讀鎖操作成功對讀鎖字段加1,就可以獲得讀鎖。

寫鎖,為鎖變量的低8位,包含3種狀態,有寫意願,寫鎖使用中,以及無。

arch_rwlock_t巧妙地將讀鎖和寫鎖壓縮在一個整形,可以通過原子指令同時對兩個鎖進行原子操作。不必另外設計一鎖對鎖變量操作進行保護。

arch_rwlock_t還巧妙地使用了spinlock的自旋和FIFO排隊特性,實現了對讀寫的排隊。

arch_rwlock_t的讀操作使用atomic_add和atomic_sub支持多個讀者對讀鎖的修改,並且可以與寫操作相容。但當上讀鎖一瞬后發現有寫意願和寫進行,就必須歸還讀鎖,進行排隊模式。排隊的讀鎖操作,在輪到的時候也不是一步到位就可以成功上讀鎖。因為這時,有可能其它CPU剛發生的寫鎖意願,盡管有其它讀寫在排隊,但這時這個剛發生寫鎖意願的CPU是不被排隊所約束的。在這種情況下,讀鎖是不可以歸還的,回這會讓同樣的情況歷史重演,使整個排隊阻塞不前。所以這個輪到的排隊讀鎖的CPU必須保持這個讀鎖,直到橫刀插入的寫鎖釋放后,馬上通行。

reader rwlock writer
1. 從spinlock排隊返回 read == 0 && write state == 0  
  read == 0 && write state == FF 1. 剛發起寫鎖操作,atomic_xchg返回的讀鎖字段仍為0,OK,沒有讀鎖進行
2. atomic_add返回,發現寫鎖字段不為0 read == 1 && write state == FF 2. 使用寫鎖
3. 自旋等待write state變為0    
  read == 1 && write state == 0 3. 歸還寫鎖。即使突然發生的寫鎖操作也不能橫刀斷入(steal),只好去排隊。
4. 馬上可以讀鎖能行。    
5. 釋放spinlock,使spinlock排隊前進。    
     

 

arch_rwlock_t的讀操作使用atomic_cmpxchg保證只有一個寫者完整進行寫鎖的修改,並且操作與任意讀操作不相容,即有任意讀操作同時進行,修改都不被接受。當有寫意願或寫鎖進行時,所有的寫鎖操作都必須和讀鎖操作平等地FIFO排隊等候。只有在一個寫鎖操作發現有讀鎖進行時,進入排隊發出寫意願(修改鎖變量的寫鎖字段),這時候這個寫鎖操作才會成為第一個排隊的操作,優先於其它后繼的排隊的操作。后繼的排隊的不論讀鎖或寫鎖的操作都是平等的。

 

spinlock不是用來保護鎖變量,而是同步臨界區queue_read_lock_slowpath以及queue_write_lock_slowpath的,對有寫鎖操作參與這一事態,進行對鎖操作的排隊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM