在驅動程式中,當多個線程同時訪問相同的資源時(驅動程式中的全域變數是一種典型的共用資源),可能會引發"競態",因此我們必須對共用資源進行並發控制。Linux核心中解決並發控制的最常用方法是自旋鎖與訊號量(絕大多數時候作為互斥鎖使用)。
自旋鎖與訊號量"類似而不類",類似說的是它們功能上的相似性,"不類"指代它們在本質和實現機理上完全不一樣,不屬於一類。
自旋鎖不會引起調用者睡眠,如果自旋鎖已經被別的執行單元保持,調用者就一直迴圈查看是否該自旋鎖的保持者已經釋放了鎖,"自旋"就是"在原地打轉"。而訊號量則引起調用者睡眠,它把進程從運行隊列上拖出去,除非獲得鎖。這就是它們的"不類"。
但是,無論是訊號量,還是自旋鎖,在任何時刻,最多隻能有一個保持者,即在任何時刻最多隻能有一個執行單元獲得鎖。這就是它們的"類似"。
鑒於自旋鎖與訊號量的上述特點,一般而言,自旋鎖適合於保持時間非常短的情況,它可以在任何上下文使用;訊號量適合於保持時間較長的情況,會只能在進程上下文使用。如果被保護的共用資源只在進程上下文訪問,則可以以訊號量來保護該共用資源,如果對共用資源的訪問時間非常短,自旋鎖也是好的選擇。但是,如 果被保護的共用資源需要在中斷上下文訪問(包括底半部即中斷處理控制代碼和頂半部即非強制中斷),就必須使用自旋鎖。
區別總結如下:
1、由於爭用訊號量的進程在等待鎖重新變為可用時會睡眠,所以訊號量適用於鎖會被長時間持有的情況。
2、相反,鎖被短時間持有時,使用訊號量就不太適宜了,因為睡眠引起的耗時可能比鎖被佔用的全部時間還要長。
3、由於執行線程在鎖被爭用時會睡眠,所以只能在進程上下文中才能擷取訊號量鎖,因為在中斷上下文中(使用自旋鎖)是不能進行調度的。
4、你可以在持有訊號量時去睡眠(當然你也可能並不需要睡眠),因為當其它進程試圖獲得同一訊號量時不會因此而死結,(因為該進程也只是去睡眠而已,而你最終會繼續執行的)。
5、在你佔用訊號量的同時不能佔用自旋鎖,因為在你等待訊號量時可能會睡眠,而在持有自旋鎖時是不允許睡眠的。
6、訊號量鎖保護的臨界區可包含可能引起阻塞的代碼,而自旋鎖則絕對要避免用來保護包含這樣代碼的臨界區,因為阻塞意味著要進行進程的切換,如果進程被切換出去後,另一進程企圖擷取本自旋鎖,死結就會發生。
7、訊號量不同於自旋鎖,它不會禁止核心搶佔(自旋鎖被持有時,核心不能被搶佔),所以持有訊號量的代碼可以被搶佔,這意味著訊號量不會對調度的等待時間帶來負面影響。
除了以上介紹的同步機制方法以外,還有BKL(大核心鎖),Seq鎖等。
BKL是一個全域自旋鎖,使用它主要是為了方便實現從Linux最初的SMP過度到細粒度加鎖機制。
Seq鎖用於讀寫共用資料,實現這樣鎖只要依靠一個序列計數器。
PS: 試圖遞迴地獲得自旋鎖必然會引起死結,申請這個資源的進程不停地瘋狂“自旋”,也無法獲得資源。
以上轉自:http://www.cnblogs.com/iceocean/articles/1610192.html