標題: Linux內核的同步機制之二--自旋鎖 [打印本頁]
作者: 51黑tt 時間: 2016-3-5 23:38
標題: Linux內核的同步機制之二--自旋鎖
自旋鎖(spinlock) 自旋鎖最多只能被一個可執行線程持有。自旋鎖不會引起調用者睡眠,如果一個執行線程試圖獲得一個已經被持有的自旋鎖,那么線程就會一直進行忙循環,一直等待下去,在那里看是否該自旋鎖的保持者已經釋放了鎖,"自旋"一詞就是因此而得名。
由于自旋鎖使用者一般保持鎖時間非常短,因此選擇自旋而不是睡眠是非常必要的,自旋鎖的效率遠高于互斥鎖。
信號量和讀寫信號量適合于保持時間較長的情況,它們會導致調用者睡眠,因此只能在進程上下文使用(_trylock的變種能夠在中斷上下文使用);而自旋鎖適合于保持時間非常短的情況,因為一個被爭用的自旋鎖使得請求它的線程在等待重新可用時自旋,特別浪費處理時間,這是自旋鎖的要害之處,所以自旋鎖不應該被長時間持有。在實際應用中自旋鎖代碼只有幾行,而持有自旋鎖的時間也一般不會超過兩次上下方切換,因線程一旦要進行切換,就至少花費切出切入兩次,自旋鎖的占用時間如果遠遠長于兩次上下文切換,我們就可以讓線程睡眠,這就失去了設計自旋鎖的意義。
如果被保護的共享資源只在進程上下文訪問,使用信號量保護該共享資源非常合適,如果對共享資源的訪問時間非常短,自旋鎖也可以。但是如果被保護的共享資源需要在中斷上下文訪問(包括底半部即中斷處理句柄和頂半部即軟中斷),就必須使用自旋鎖。
自旋鎖保持期間是搶占失效的,而信號量和讀寫信號量保持期間是可以被搶占的。自旋鎖只有在內核可搶占或SMP的情況下才真正需要,在單CPU且不可搶占的內核下,自旋鎖的所有操作都是空操作。
一個執行單元要想訪問被自旋鎖保護的共享資源,必須先得到鎖,在訪問完共享資源后,必須釋放鎖。如果在獲取自旋鎖時,沒有任何執行單元保持該鎖,那么將立即得到鎖;如果在獲取自旋鎖時鎖已經有保持者,那么獲取鎖操作將自旋在那里,直到該自旋鎖的保持者釋放了鎖。
無論是互斥鎖,還是自旋鎖,在任何時刻,最多只能有一個保持者,也就說,在任何時刻最多只能有一個執行單元獲得鎖。自旋鎖的實現和體系結構密切相關,代碼一般通過匯編實現,定義在文件<asm/spinlock.h>,實際用到的接口定義在文件夾<linux/spinlock.h> 中, 自旋鎖的API有:
spin_lock_init(x)
該宏用于初始化自旋鎖x。自旋鎖在真正使用前必須先初始化。該宏用于動態初始化指定的。
DEFINE_SPINLOCK(x)
該宏聲明一個自旋鎖x并初始化它。該宏在2.6.11中第一次被定義,在先前的內核中并沒有該宏。
SPIN_LOCK_UNLOCKED
該宏用于靜態初始化一個自旋鎖。
DEFINE_SPINLOCK(x)等同于spinlock_t x = SPIN_LOCK_UNLOCKEDspin_is_locked(x)
該宏用于判斷自旋鎖x是否已經被某執行單元保持(即被鎖),如果是,返回真,否則返回假。
spin_unlock_wait(x)
該宏用于等待自旋鎖x變得沒有被任何執行單元保持,如果沒有任何執行單元保持該自旋鎖,該宏立即返回,否則將循環在那里,直到該自旋鎖被保持者釋放。
spin_trylock(lock)
該宏盡力獲得自旋鎖lock,如果能立即獲得鎖,它獲得鎖并返回真,否則不能立即獲得鎖,立即返回假。它不會自旋等待lock被釋放。
spin_lock(lock)
該宏用于獲得自旋鎖lock,如果能夠立即獲得鎖,它就馬上返回,否則,它將自旋在那里,直到該自旋鎖的保持者釋放,這時,它獲得鎖并返回。總之,只有它獲得鎖才返回。
spin_lock_irqsave(lock, flags)
該宏獲得自旋鎖的同時把標志寄存器的值保存到變量flags中并失效本地中斷。
spin_lock_irq(lock)
該宏類似于spin_lock_irqsave,只是該宏不保存標志寄存器的值。禁止本地中斷并獲取指定的鎖
spin_lock_bh(lock)
該宏在得到自旋鎖的同時失效本地軟中斷。
spin_unlock(lock)
該宏釋放自旋鎖lock,它與spin_trylock或spin_lock配對使用。如果spin_trylock返回假,表明沒有獲得自旋鎖,因此不必使用spin_unlock釋放。
spin_unlock_irqrestore(lock, flags)
該宏釋放自旋鎖lock的同時,也恢復標志寄存器的值為變量flags保存的值。它與spin_lock_irqsave配對使用。
spin_unlock_irq(lock)
該宏釋放自旋鎖lock的同時,并激活本地中斷。它與spin_lock_irq配對應用。
spin_unlock_bh(lock)
該宏釋放自旋鎖lock的同時,也使能本地的軟中斷。它與spin_lock_bh配對使用。
spin_trylock_irqsave(lock, flags)
該宏如果獲得自旋鎖lock,它也將保存標志寄存器的值到變量flags中,并且失效本地中斷,如果沒有獲得鎖,它什么也不做。
因此如果能夠立即獲得鎖,它等同于spin_lock_irqsave,如果不能獲得鎖,它等同于spin_trylock。如果該宏獲得自旋鎖lock,那需要使用spin_unlock_irqrestore來釋放。
spin_trylock_irq(lock)
該宏類似于spin_trylock_irqsave,只是該宏不保存標志寄存器。如果該宏獲得自旋鎖lock,需要使用spin_unlock_irq來釋放。
spin_trylock_bh(lock)
該宏如果獲得了自旋鎖,它也將失效本地軟中斷。如果得不到鎖,它什么也不做。因此,如果得到了鎖,它等同于spin_lock_bh,如果得不到鎖,它等同于spin_trylock。如果該宏得到了自旋鎖,需要使用spin_unlock_bh來釋放。
spin_can_lock(lock)
該宏用于判斷自旋鎖lock是否能夠被鎖,它實際是spin_is_locked取反。如果lock沒有被鎖,它返回真,否則,返回假。該宏在2.6.11中第一次被定義,在先前的內核中并沒有該宏。
自旋鎖的基本使用如下:
spinlock_t myr_lock = SPIN_LOCK_UNLOCKED;
spin_lock(&myr_lock);
/*臨界區*/
spin_unlock(&myr_lock);
因為自旋鎖在同一時刻至多被一個執行線程持有,所以一個時刻只能有一個線程位于臨界區,這就為多處理器提供了防止并發訪問所需的保護機制,但是在單處理器上,編譯的時候不會加入自旋鎖。它僅僅被當作一個設置內核搶占機制是否被啟用的開關。注意,Linux內核實現的自旋鎖是不可遞歸的,這一點不同于自旋鎖在其他操作系統中的實現,如果你想得到一個你正持有的鎖,你必須自旋,等待你自己釋放這個鎖,但是你處于自旋忙等待中,所以永遠沒有機會釋放鎖,于是你就被自己鎖死了,一定要注意!
自旋鎖可以用在中斷處理程序中,但是在使用時一定要在獲取鎖之前,首先禁止本地中斷(當前處理器上的中斷),否則中斷處理程序就可能打斷正持有鎖的內核代碼,有可能會試圖支爭用這個已經被持有的自旋鎖。這樣一來,中斷處理程序就會自旋,等待該鎖重新可用,但是鎖的持有者在這個中斷處理程序執行完畢之前不可能運行,這就會造成雙重請求死鎖。
自旋鎖與下半部:由于下半部(中斷程序下半部)可以搶占進程上下文中的代碼,所以當下半部和進程上下文共享數據時,必須對進程上下文中的共享數據進行保護,所以需要加鎖的同時還要禁止下半部執行。同樣,由于中斷處理程序可以搶占下半部,所以如果中斷處理程序和下半部共享數據,那么就必須在獲取恰當的鎖的同時還要禁止中斷。對于軟中斷,無論是否同種類型,如果數據被軟中斷共享,那么它必須得到鎖的保護,因為同種類型的兩個軟中斷也可以同進運行在一個系統的多個處理器上。但是,同一個處理器上的一個軟中斷絕不會搶占另一個軟中斷,因此,根本不需要禁止下半部。
歡迎光臨 (http://www.zg4o1577.cn/bbs/) |
Powered by Discuz! X3.1 |
主站蜘蛛池模板:
婷婷久
|
就操在线
|
视频在线一区
|
成人一区精品
|
欧美激情欧美激情在线五月
|
色视频在线播放
|
亚洲v日韩v综合v精品v
|
国产在线精品一区二区
|
一区二区视频在线
|
成年无码av片在线
|
欧美日韩在线免费
|
久久精品com
|
伦理午夜电影免费观看
|
最新中文字幕第一页视频
|
国产福利在线播放
|
福利一区二区
|
超碰免费在线观看
|
在线日韩精品视频
|
精品国产91久久久久久
|
中文字幕日韩一区
|
国产精品久久
|
狠狠av|
国产精品久久久久久久久久免费看
|
欧美激情网站
|
大乳boobs巨大吃奶挤奶
|
国产视频一区二区
|
在线观看欧美日韩视频
|
国产激情片在线观看
|
日韩国产一区二区三区
|
999久久久久久久久6666
|
久久逼逼
|
成人午夜在线视频
|
午夜播放器在线观看
|
99久久婷婷国产综合精品电影
|
成人精品
|
久久久久久蜜桃一区二区
|
97国产精品视频
|
一区二区在线观看免费视频
|
亚洲精品一二三
|
亚洲综合视频
|
欧美精品福利视频
|