linux裝置驅動學習(六)–並發與竟態2

來源:互聯網
上載者:User

自旋鎖:和訊號量不同,自旋鎖可以在不能休眠的代碼中使用,比如中斷處理常式。自旋鎖通常實現為某個整數值中的某個位。希望獲得某特定鎖的代碼測試相關的位。如果鎖可用,則鎖定位被設定,而代碼進入臨界區。相反,如果鎖定被其他人獲得,則代碼進入忙迴圈並重複檢查這個鎖。以上測試並設定的操作必須以原子方式進行。

自旋鎖API

使用自旋鎖必須包含標頭檔<linux/spinlock.h>,鎖的類型為spinlock_t類型

定義同時完成初始化:

 spinlock_t my_lock = SPIN_LOCK_UNLOCKED;

或在運行前初始化:

void spin_lock_init(spinlock_t *lock);

在進入臨界區之前,通過如下代碼獲得需要的鎖:

void spin_lock(spinlock_t *lock);

上面兩條語句一般同時運用:

void spin_lock_init(spinlock_t *lock);

void spin_lock(spinlock_t *lock);

注意所有自旋鎖在本質都是不可中斷的。一旦調用spin_lock,在獲得鎖之前一直為自旋狀態。

釋放鎖void spin_unlock(spinlock_t *lock);

在驅動擁有自旋鎖工作在臨界區的時候下可能會出現如下情況,使驅動程式丟掉處理器從而影響系統效能或導致系統死結。例如調用一個函數(copy_from_user),這個函數導致進程進入休眠狀態。或者,發生了核心搶佔,更高優先順序的進程搶佔了處理器,這樣在這段時間內我們的驅動程式將始終持有這個自旋鎖,這是如果有其他進程試圖來獲得該鎖,那麼該進程要等待很長時間。

使用於自旋鎖的規則:

1.任何自旋鎖的代碼必須是原子的,它不能休眠,事實上它不能因為任何原因放棄處理器,除了中斷處理常式外(某些情況此時也不可以放棄處理器)。

2.核心搶佔的情況有自旋鎖代碼本身進行處理——應該理解為對於核心搶佔的處理在自旋鎖所保護的臨界區內進行,所以任何時候,只要核心代碼擁有自旋鎖,在相關處理器上的搶佔就被禁止.

3.訊號量可以用於休眠的情況,而自旋鎖基本上不可以用於休眠。核心中有許多用於休眠的函數,如在於使用者空間發生資料互動時,等待I/O口完成任務時,kmallo分配記憶體時。所以在編寫需要在自旋鎖下執行的代碼時,必須注意每一個調用函數。

4.在中斷處理常式中:當我們的驅動程式在擁有自旋鎖的情況下對裝置進行訪問時,裝置出現一個中斷,它導致中斷處理常式開始執行,在中斷處理常式訪問裝置前也需要獲得該鎖,這時中斷常式自旋時,非終端代碼將沒有任何機會來釋放這個鎖,處理器將永遠自旋下去。所以我們我們需要在擁有該鎖時,禁止所有中斷(僅在本地CPU上)。

5.自旋鎖必須在可能的最短時間內擁有。

 自旋鎖函數

void spin_lock(spinlock_t *lock);

void spin_lock_irqsave(spinlock_t *lock,int flags);  //獲得鎖,禁止中斷,儲存當前中斷狀態

void spin_lock_irq(spinlock_t *spin);//獲得鎖,禁止中斷,在確保沒有任何其他代碼禁止本地處理器中斷時運用

void spin_lock_bh(spinlock_t *lock);//禁止非強制中斷,但是會讓硬中斷保持開啟。

如果我們有一個自旋鎖,它可以被運行在(硬體或軟體中斷)上下文中的代碼獲得,則必須使用某個禁止中斷的spin_lock形式。如果我們不會在硬體中斷處理常式中訪問自旋鎖,但可能在軟體中斷中訪問,則應該使用spin_lock_bh(spinlock_t *lock)以避免死結同時還能服務硬中斷。

釋放鎖spin_unlock_irqrestore(spinlock_t *lock,int flags);

spin_unlock_irq(spinlock_t *lock);

 

int spin_trylock(spinlock_t *lock);

int spin_trylock_bh(spinlock_t *lock);

不會阻塞,在沒獲得鎖的情況下,直接返回。

 

讀寫鎖(略)

 

關於鎖的一些重要規則,這些規則只有到實踐中才能夠真正掌握,這裡只是瞭解一下大致的概念。

1.如果獲得鎖的進程要調用其他同樣試圖獲得該鎖的進程,代碼就會死結。不論訊號還自旋鎖都不允許擁有者第二次獲得這個鎖。

2.對於裝置內部的靜態函數在編寫時,都假定調用者已經擷取了相關的鎖,而提供給外部調用的函數則必須顯示的處理鎖定,在編寫那些假定調用者已處理了鎖定的內建函式時,我們應該顯示地說明這種假定。

在scull的例子中,所採用的規則是:由系統調用直接調用的那些函數均要獲得訊號量,以便保護要訪問的資料結構。而其他內建函式只會由其他的scull函數調用,且假定訊號量已經獲得。

3.保持對鎖的順序獲得,千萬避免交叉申請,否則會導致申請的進程全部死結。

4.先獲得局部鎖,比如裝置鎖,然後再獲得深度更深的鎖。

5.如果我們擁有訊號量和自旋鎖的組合,則必須首先獲得訊號量,因為如果先獲得自旋鎖,在保護區內down掉訊號量(可能導致休眠)則對於鎖來說是嚴重錯誤的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.