關(guān)于Linux自旋鎖
一些問答
A: 信號量和讀寫信號量適合于保持時間較長的情況,它們會導致調(diào)用者睡眠,因此只能在進程上下文使用(_trylock的變種能夠在中斷上下文使用)
Q:?這個確實如此, 如果在中斷上下文中,使用信號量(也就是在中斷處理函數(shù)中使用信號量) ,可能會導致死鎖 , 而spinlock ,由于是自旋,不會睡眠,而且,spinlock保護的代碼都非常短 , 所以都能很快獲得spinlock ,不會造成死鎖。
A: 而自旋鎖適合于保持時間非常短的情況,它可以在任何上下文使用。
Q:?確實如此!
A: 如果被保護的共享資源只在進程上下文訪問,使用信號量保護該共享資源非常合適,如果對共享資源的訪問時間非常短,自旋鎖也可以。
Q:?參考了一些driver的代碼,確實應(yīng)該遵循這個原則, 比如:
spin_lock_irq(&rtc_lock);//禁止本地中斷, 因為返回給用戶的就是這個rtc_irq_data ,如果恰好發(fā)生了中斷,這個value就被竄改了
data = rtc_irq_data; /* 由中斷函數(shù)更新*/
//顯然這里有竟態(tài)條件,這里要訪問,但是中斷處理函數(shù)也要修改(write) ,所以就要禁止中斷
rtc_irq_data = 0;
spin_unlock_irq(&rtc_lock);
顯然這里用自旋鎖,就比用信號量強。 因為中斷函數(shù),更新rtc_irq_data的速度很快, 這里馬上就可以獲得lock,最主要的原因還是 在中斷處理函數(shù)中不能使用信號量,防止死鎖。
A: 自旋鎖保持期間是搶占失效的,
Q:?自旋鎖搶占失效的意思, 我的理解是,比如2.6 kernel ,如果某個kernel線程(可能就是某個用戶進程的延伸) ,如果獲得了某個自旋鎖,即使有更高優(yōu)先級的進程需要調(diào)度, 當前的獲得了自旋鎖的線程,也不會放棄這個鎖,或者說,也不會失去CPU 。
A: 而信號量和讀寫信號量保持期間是可以被搶占的。
Q:?如果是這樣,如果高優(yōu)先級的進程也恰好也要獲取信號量呢,而剛才那個進程并沒有釋放信號量???
便于說明 :A表示低優(yōu)先級的, B表示高優(yōu)先級。 當a 獲得信號量以后, 進入臨界區(qū) , 就在還沒有退出臨界區(qū)時候, 被B搶占 , B恰好也要獲取信號量, 如果A沒有釋放信號量,B 就必然一直等著,進入sleep狀態(tài) , 直到又一次發(fā)生了進程切換, 等到A 再一次被調(diào)度的時候, A 從臨界區(qū)出來 ,釋放信號量 , 又一次調(diào)度 ; 等到最后又調(diào)度B的時候 , B 終于可以獲得信號量了。
不知道我這個情景分析的對不對呢? 如果對的話, 這樣看來, 在剛才的情景之下, 用自旋鎖反而更好一些, 防止了搶占,也能使A進程更快的從臨界區(qū)出來。
一些關(guān)鍵API函數(shù)
spin_lock(lock)
該宏用于獲得自旋鎖lock,如果能夠立即獲得鎖,它就馬上返回,否則,它將自旋在那里,直到該自旋鎖的保持者釋放,這時,它獲得鎖并返回??傊?,只有它獲得鎖才返回。
spin_lock_irqsave(lock, flags)
該宏獲得自旋鎖的同時把標志寄存器的值保存到變量flags中并失效本地中斷。
spin_lock_irq(lock)
該宏類似于spin_lock_irqsave,只是該宏不保存標志寄存器的值。
實際上,這一段應(yīng)該能很好的說明這個問題了, “spin_lock?與?spin_lock_irq?的區(qū)別”。