日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

6.2自旋锁

發布時間:2024/1/8 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 6.2自旋锁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 自旋鎖
  • 自旋鎖API函數
  • 死鎖兩種情況
    • 被自旋鎖保護的臨界區調用引起睡眠和阻塞的API 函數
    • 中斷造成的死鎖
  • 下半部競爭處理函數
  • 自旋鎖使用的注意事項

自旋鎖

原子操作只能對整形變量或者位進行保護,但是,在實際的使用環境中怎么可能只有整形變量或位這么簡單的臨界區。舉個最簡單的例子,設備結構體變量就不是整型變量,我們對于結構體中成員變量的操作也要保證原子性,在線程 A 對結構體變量使用期間,應該禁止其他的線程來訪問此結構體變量,這些工作原子操作都不能勝任,需要本節要講的鎖機制,在 Linux內核中就是自旋鎖。
當一個線程要訪問某個共享資源的時候首先要先獲取相應的鎖,鎖只能被一個線程持有,只要此線程不釋放持有的鎖,那么其他的線程就不能獲取此。對于自旋鎖而言,如果自旋鎖正在被線程 A 持有,線程 B 想要獲取自旋鎖,那么線程 B 就會處于忙循環-旋轉-等待狀態,線程 B 不會進入休眠狀態或者說去做其他的處理,而是會一直傻傻的在那里“轉圈圈”的等待鎖可用。比如現在有個公用電話亭,一次肯定只能進去一個人打電話,現在電話亭里面有人正在打電話,相當于獲得了自旋鎖。此時你到了電話亭門口,因為里面有人,所以你不能進去打電話,相當于沒有獲取自旋鎖,這個時候你肯定是站在原地等待,你可能因為無聊的等待而轉圈圈消遣時光,反正就是哪里也不能去,要一直等到里面的人打完電話出來。終于,里面的人打完電話出來了,相當于釋放了自旋鎖,這個時候你就可以使用電話亭打電話了,相當于獲取到了自旋鎖。
自旋鎖的“自旋”也就是“原地打轉”的意思,“原地打轉”的目的是為了等待自旋鎖可以用,可以訪問共享資源。把自旋鎖比作一個變量 a,變量 a=1 的時候表示共享資源可用,當 a=0的時候表示共享資源不可用。現在線程 A 要訪問共享資源,發現 a=0(自旋鎖被其他線程持有),那么線程 A 就會不斷的查詢 a 的值,直到 a=1。從這里我們可以看到自旋鎖的一個缺點:那就等待自旋鎖的線程會一直處于自旋狀態,這樣會浪費處理器時間,降低系統性能,所以自旋鎖的持有時間不能太長。所以自旋鎖適用于短時期的輕量級加鎖,如果遇到需要長時間持有鎖的場景那就需要換其他的方法了,這個我們后面會講解。
Linux 內核使用結構體 spinlock_t 表示自旋鎖,結構體定義如下所示:

64 typedef struct spinlock {65 union {66 struct raw_spinlock rlock;6768 #ifdef CONFIG_DEBUG_LOCK_ALLOC69 # define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))70 struct {71 u8 __padding[LOCK_PADSIZE];72 struct lockdep_map dep_map;73 };74 #endif75 }; 76 } spinlock_t;

在使用自旋鎖之前,肯定要先定義一個自旋鎖變量,定義方法如下所示:
spinlock_t lock; //定義自旋鎖
定義好自旋鎖變量以后就可以使用相應的 API 函數來操作自旋鎖。

自旋鎖API函數

最基本的自旋鎖 API 函數如表 47.3.2.1 所示:

函數描述
DEFINE_SPINLOCK(spinlock_t lock)定義并初始化一個自選變量。
int spin_lock_init(spinlock_t *lock)初始化自旋鎖。
void spin_lock(spinlock_t *lock)獲取指定的自旋鎖,也叫做加鎖。
void spin_unlock(spinlock_t *lock)釋放指定的自旋鎖。
int spin_trylock(spinlock_t *lock)嘗試獲取指定的自旋鎖,如果沒有獲取到就返回 0
int spin_is_locked(spinlock_t *lock)檢查指定的自旋鎖是否被獲取,如果沒有被獲取就返回非 0,否則返回 0。

死鎖兩種情況

被自旋鎖保護的臨界區調用引起睡眠和阻塞的API 函數

上圖的自旋鎖API函數適用于SMP或支持搶占的單CPU下線程之間的并發訪問,也就是用于線程與線程之間,**被自旋鎖保護的臨界區一定不能調用任何能夠引起睡眠和阻塞的API 函數,**否則的話會可能會導致死鎖現象的發生。自旋鎖會自動禁止搶占,也就說當線程 A得到鎖以后會暫時禁止內核搶占。如果線程 A 在持有鎖期間進入了休眠狀態,那么線程 A 會自動放棄 CPU 使用權。線程 B 開始運行,線程 B 也想要獲取鎖,但是此時鎖被 A 線程持有,而且內核搶占還被禁止了!線程 B 無法被調度出去,那么線程 A 就無法運行,鎖也就無法釋放,好了,死鎖發生了!

中斷造成的死鎖

上圖API 函數用于線程之間的并發訪問,如果此時中斷也要插一腳,中斷也想訪問共享資源,那該怎么辦呢?首先可以肯定的是,中斷里面可以使用自旋鎖,但是在中斷里面使用自旋鎖的時候,在獲取鎖之前一定要先禁止本地中斷(也就是本 CPU 中斷,對于多核 SOC來說會有多個 CPU 核),否則可能導致鎖死現象的發生。

前,線程 A 是不可能執行的,線程 A 說“你先放手”,中斷說“你先放手”,場面就這么僵持著,死鎖發生!
最好的解決方法就是獲取鎖之前關閉本地中斷,Linux 內核提供了相應的 API 函數,如表47.3.2.2 所示:

函數描述
void spin_lock_irq(spinlock_t *lock)禁止本地中斷,并獲取自旋鎖。
void spin_unlock_irq(spinlock_t *lock)激活本地中斷,并釋放自旋鎖。
void spin_lock_irqsave(spinlock_t *lock,unsigned long flags)保存中斷狀態,禁止本地中斷,并獲取自旋鎖。
void spin_unlock_irqrestore(spinlock_t*lock, unsigned long flags)將中斷狀態恢復到以前的狀態,并且激活本地中斷,釋放自旋鎖。

使用 spin_lock_irq/spin_unlock_irq 的時候需要用戶能夠確定加鎖之前的中斷狀態,但實際上內核很龐大,運行也是“千變萬化”,我們是很難確定某個時刻的中斷狀態,因此不推薦使用spin_lock_irq/spin_unlock_irq。建議使用 spin_lock_irqsave/spin_unlock_irqrestore,因為這一組函數會保存中斷狀態,在釋放鎖的時候會恢復中斷狀態。一般在線程中使用 spin_lock_irqsave/
spin_unlock_irqrestore,在中斷中使用 spin_lock/spin_unlock,示例代碼如下所示:

1 DEFINE_SPINLOCK(lock) /* 定義并初始化一個鎖 */ 2 3 /* 線程 A */ 4 void functionA (){5 unsigned long flags; /* 中斷狀態 */6 spin_lock_irqsave(&lock, flags) /* 獲取鎖 */7 /* 臨界區 */8 spin_unlock_irqrestore(&lock, flags) /* 釋放鎖 */ 9 } 10 11 /* 中斷服務函數 */ 12 void irq() {13 spin_lock(&lock) /* 獲取鎖 */14 /* 臨界區 */15 spin_unlock(&lock) /* 釋放鎖 */ 16 }

下半部競爭處理函數

下半部(BH)也會競爭共享資源,有些資料也會將下半部叫做底半部。關于下半部后面的章節會講解,如果要在下半部里面使用自旋鎖,可以使用表 47.3.2.3 中的 API 函數:

函數描述
void spin_lock_bh(spinlock_t *lock)關閉下半部,并獲取自旋鎖。
void spin_unlock_bh(spinlock_t *lock)打開下半部,并釋放自旋鎖。

自旋鎖使用的注意事項

①、因為在等待自旋鎖的時候處于“自旋”狀態,因此鎖的持有時間不能太長,一定要短,否則的話會降低系統性能。如果臨界區比較大,運行時間比較長的話要選擇其他的并發處理方式,比如稍后要講的信號量和互斥體。
②、自旋鎖保護的臨界區內不能調用任何可能導致線程休眠的 API 函數,否則的話可能導致死鎖。
③、不能遞歸申請自旋鎖,因為一旦通過遞歸的方式申請一個你正在持有的鎖,那么你就必須“自旋”,等待鎖被釋放,然而你正處于“自旋”狀態,根本沒法釋放鎖。結果就是自己把自己鎖死了!
④、在編寫驅動程序的時候我們必須考慮到驅動的可移植性,因此不管你用的是單核的還是多核的 SOC,都將其當做多核 SOC 來編寫驅動程序。

總結

以上是生活随笔為你收集整理的6.2自旋锁的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。