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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

kernel并发控制:自旋锁、互斥体、中断屏蔽

發布時間:2023/12/15 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 kernel并发控制:自旋锁、互斥体、中断屏蔽 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

1.?中斷屏蔽(關中斷)

在單 CPU 范圍內避免競態的一種簡單方法是在進入臨界區之前屏蔽系統的中斷。

CPU 一般都具備屏蔽中斷和打開中斷的功能,這項功能可以保證正在執行的內核執行路徑不被中斷處理程序所搶占,防止某些競態條件的發生。具體而言,中斷屏蔽將使得中斷與進程之間的并發不再發生,而且,由于 Linux 內核的進程調度等操作都依賴中斷來實現,內核搶占進程之間的并發也就得以避免了。

由于 Linux 系統的異步 I/O、進程調度等很多重要操作都依賴于中斷,中斷對于內核的運行非常重要,在屏蔽中斷期間所有的中斷都無法得到處理,因此長時間屏蔽中斷是很危險的,有可能造成數據丟失甚至系統崩潰。這就要求在屏蔽了中斷之后,當前的內核執行路徑應當盡快地執行完臨界區的代碼。

local_irq_disable()和 local_irq_enable()都只能禁止和使能本 CPU 內的中斷, 因此,并不能解決 SMP 多 CPU 引發的競態。因此,單獨使用中斷屏蔽通常不是一種值得推薦的避免競態的方法,它適宜與自旋鎖聯合使用。

如果只是想禁止中斷的底半部,應使用 local_bh_disable(), 使能底半部應該調用 local_bh_enable()。

?

?

2.?自旋鎖

?自旋鎖(spin lock)是一個典型的對臨界資源的互斥手段,它的名稱來源于它的特性。為了獲得一個自旋鎖,在某CPU上運行的代碼需先執行一個原子操作,該操作測試并設置(test-and-set)某個內存變量,由于它是原子操作,所以在該操作完成之前其它CPU不可能訪問這個內存變量。如果測試結果表明鎖已經空閑,則程序獲得這個自旋鎖并繼續執行。如果測試結果表明鎖仍被占用,程序將在一個小的循環內重復這個“測試并設置(test-and-set)”操作,即開始“自旋”。最后,鎖的所有者通過重置該變量釋放這個自旋鎖,于是,某個等待的test-and-set操作向其調用者報告鎖已釋放。

?

理解自旋鎖最簡單的方法是把它作為一個變量看待,這個變量把一個臨界區或者標記為“我當前在另一個CPU上運行,請稍等一會”,或者標記為“我當前不在運行,可以被使用”。如果1號CPU首先進入該例程,它就獲取該自旋鎖;當2號CPU試圖進入同一個例程時,該自旋鎖告訴它自己已為1號CPU所持有,需等到1號CPU釋放自己后才能進入。

?

自旋鎖主要針對SMP或單CPU且內核可搶占的情況,對于單CPU且內核不可搶占的系統自旋鎖退化為空操作。

盡管自旋鎖可以保證臨界區不受別的CPU和本CPU的搶占進程打擾,但是得到鎖的代碼路徑在執行臨界區的時候還可能受到中斷和底半部影響,此時應該使用 自旋鎖的衍生操作。

?

驅動工程師應謹慎使用自旋鎖, 而且在使用中還要特別注意如下幾個問題。

1) 自旋鎖實際上是忙等鎖, 當鎖不可用時, CPU一直循環執行“測試并設置”該鎖直到可用而取得該鎖, CPU在等待自旋鎖時不做任何有用的工作, 僅僅是等待。 因此, 只有在占用鎖的時間極短的情況下,使用自旋鎖才是合理的。 當臨界區很大, 或有共享設備的時候, 需要較長時間占用鎖, 使用自旋鎖會降低系統的性能。

2) 自旋鎖可能導致系統死鎖。 引發這個問題最常見的情況是遞歸使用一個自旋鎖, 即如果一個已經擁有某個自旋鎖的CPU想第二次獲得這個自旋鎖, 則該CPU將死鎖。

3) 在自旋鎖鎖定期間不能調用可能引起進程調度的函數。 如果進程獲得自旋鎖之后再阻塞, 如調用copy_from_user() 、 copy_to_user() 、 kmalloc() 和msleep() 等函數, 則可能導致內核的崩潰。

4) 在單核情況下編程的時候, 也應該認為自己的CPU是多核的, 驅動特別強調跨平臺的概念。 比如, 在單CPU的情況下, 若中斷和進程可能訪問同一臨界區, 進程里調用spin_lock_irqsave() 是安全的, 在中斷里其實不調用spin_lock() 也沒有問題, 因為spin_lock_irqsave() 可以保證這個CPU的中斷服務程序不可能執行。 但是, 若CPU變成多核, spin_lock_irqsave() 不能屏蔽另外一個核的中斷, 所以另外一個核就可能造成并發問題。 因此, 無論如何, 我們在中斷服務程序里也應該調用spin_lock() 。

?

?

3.?互斥體

互斥體實現了“互相排斥”(mutual exclusion)同步的簡單形式(所以名為互斥體(mutex))?;コ怏w禁止多個線程同時進入受保護的代碼“臨界區”(critical section)。因此,在任意時刻,只有一個線程被允許進入這樣的代碼保護區。

任何線程在進入臨界區之前,必須獲取(acquire)與此區域相關聯的互斥體的所有權。如果已有另一線程擁有了臨界區的互斥體,其他線程就不能再進入其中。這些線程必須等待,直到當前的屬主線程釋放(release)該互斥體。

新的Linux內核傾向于直接使用互斥體,而不是信號量作為互斥。

?

?

4.?自旋鎖和互斥體的區別

自旋鎖和互斥鎖都是解決互斥問題的基本手段,這兩種所的區別:

1)互斥鎖和自旋鎖屬于不同層次的互斥手段,前者的實現依賴于后者,在互斥體本身的實現上,為了保證互斥體結構存取的原子性,需要自旋鎖來互斥,因此自旋鎖屬于更底層的操作。

2)互斥鎖是進程級別的,用于對各進程之間對資源的互斥,雖然也在內核中,但是該內核執行路徑是以進程的身份,代表進程來爭奪資源的,如果競爭失敗,會發生進程上下文的切換,當前進程進入睡眠狀態,CPU將運行于其他進程。由于進程上下文切換開銷比較大,因此進程占用資源時間較長時用互斥鎖才是比較好的選擇。

3)當要保護的臨界區訪問時間很短時,用自旋鎖是非常方便的,因為它可以節省上下文切換的開銷。但是CPU如果得不到自旋鎖會忙等執行臨界區解鎖為止,所以要求鎖不能再臨界區長時間停留。

?

由此, 可以總結出自旋鎖和互斥體選用的3項原則。

1) 當鎖不能被獲取到時, 使用互斥體的開銷是進程上下文切換時間, 使用自旋鎖的開銷是等待獲取自旋鎖(由臨界區執行時間決定) 。 若臨界區比較小, 宜使用自旋鎖, 若臨界區很大, 應使用互斥體。

2) 互斥體所保護的臨界區可包含可能引起阻塞(或睡眠)的代碼, 而自旋鎖則絕對要避免用來保護包含這樣代碼的臨界區。?

3) 互斥體存在于進程上下文, 因此, 如果被保護的共享資源需要在中斷或軟中斷情況下使用, 則在互斥體和自旋鎖之間只能選擇自旋鎖。 當然, 如果一定要使用互斥體, 則只能通過mutex_trylock() 方式進行, 不能獲取就立即返回以避免阻塞。

?

?

Linux內核中解決并發控制的最常用方法是自旋鎖與信號量(絕大多數時候作為互斥體使用)。

1)自旋鎖與信號量"類似而不類",類似說的是它們功能上的相似性,"不類"指代它們在本質和實現機理上完全不一樣,不屬于一類。

2)自旋鎖不會引起調用者睡眠,如果自旋鎖已經被別的執行單元保持,調用者就一直循環查看是否該自旋鎖的保持者已經釋放了鎖,"自旋"就是"在原地打轉"。而信號量則引起調用者睡眠,它把進程從運行隊列上拖出去,除非獲得鎖。這就是它們的"不類"。

3)但是,無論是信號量,還是自旋鎖,在任何時刻,最多只能有一個保持者,即在任何時刻最多只能有一個執行單元獲得鎖。這就是它們的"類似"。

4)鑒于自旋鎖與信號量的上述特點,一般而言:

  • 自旋鎖適合于保持時間非常短的情況,它可以在任何上下文使用;信號量適合于保持時間較長的情況,且只能在進程上下文使用。

  • 如果被保護的共享資源只在進程上下文訪問,則可以以信號量來保護該共享資源,如果對共享資源的訪問時間非常短,自旋鎖也是好的選擇。

  • 但是,如果被保護的共享資源需要在中斷上下文訪問(包括底半部、軟中斷),就必須使用自旋鎖。

?

?

?

總結

以上是生活随笔為你收集整理的kernel并发控制:自旋锁、互斥体、中断屏蔽的全部內容,希望文章能夠幫你解決所遇到的問題。

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