Linux 設備驅動 ====> 併發控制 --- 自旋鎖

自旋鎖的使用

自旋鎖(spin_lock)是一種典型的對臨界資源進行互斥訪問的手段,顧名思義,爲了獲得一個自旋鎖,在某CPU上運行的代碼需要先執行一個原子操作,該操作測試並設置某個內存變量,在該操作完成之前其他執行單元不可能訪問到這個內存變量。

如果測試結果表明鎖已經空閒,則程序獲得這個自旋鎖並繼續執行;如果測試表明鎖仍被佔用,程序將在一個小的循環內重複這個“測試並設置”操作,就是“自旋”的動作,就是原地打轉。當自旋鎖的持有者通過重置該變量釋放這個自旋鎖後,某個等待的“測試並設置”操作向其調用者報告鎖已經釋放。

Linux中自旋鎖的操作

1. 定義自旋鎖

spinlock_t lock;

2 初始化自旋鎖

spin_lock_init(lock);

用於動態初始化自旋鎖。

3. 獲得自旋鎖

spin_lock(lock);

該宏用於獲得自旋鎖lock,如果能夠立即獲得鎖,馬上返回,否則,它將自旋在那裏直到鎖被釋放。

spin_trylock(lock);

嘗試獲得自旋鎖lock,如果能後立即獲得鎖,返回真,否則立即返回假,也就是說不會再“原地打轉”。

4. 釋放自旋鎖

spin_unlock(lock);

釋放自旋鎖lock,與lock和trylock配套使用。

5. 用法

  1. //declear a spin lock  
  2. spinlock_t lock;  
  3. spin_lock_init(&lock);  
  4.   
  5. spin_lock(&lock);        //獲得自旋鎖  
  6. ...                      //臨界區  
  7. spin_unlock(&lock);      //解鎖  

自旋鎖主要用於SMP或者單CPU內核搶佔的情況下使用。

驅動工程師應謹慎使用,下面是需要注意的地方:

1. 自旋鎖是忙等待,在得不到鎖的時候會一直“測試並設置”,這樣的話如果長時間得不到鎖會浪費系統資源,所以適合用在等待時間比較短的情況下,不然會降低系統的性能。

2. 自旋鎖可能會導致系統死鎖。當2次試圖獲得這個自旋鎖的時候,CPU會死鎖。

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


下面舉例說明使用自旋鎖實現設備只能被一個進程打開。

我們還是沿用之前的globalmem的例子加以修改

  1. int open_count = 0; //declear open times  
  2. spinlock_t lock;  
  3.   
  4. int globalmem_open(struct inode *inode, struct file *filp)  
  5. {  
  6.     spin_lock(&lock);  
  7.     if(open_count) {    // already open  
  8.         printk(KERN_ERR "already open!\n");  
  9.         spin_unlock(&lock);  
  10.         return -EBUSY;  
  11.     }  
  12.     open_count++;  
  13.     spin_unlock(&lock);  
  14.     printk(KERN_INFO "globalmem open!\n");  
  15.     filp->private_data = globalmem_devp;   
  16.     return 0;  
  17. }  
  18.   
  19. int globalmem_release(struct inode *inode ,struct file *filp)  
  20. {  
  21.     spin_lock(&lock);  
  22.     open_count--;  
  23.     spin_unlock(&lock);  
  24.     printk(KERN_INFO "globalmem release!\n");  
  25.     return 0;  
  26. }  

在init函數中初始化

  1. int globalmem_init(void)  
  2. {  
  3.     int result;  
  4.     spin_lock_init(&lock);  

然後我們重新編譯並添加模塊,然後使用上篇中的測試app來測試,當我們運行測試程序的時候,馬上再去打開globalmem的時候會提示設備忙。

[plain] view plaincopy
  1. jay@jay:/dev$ cat globalmem   
  2. jay@jay:/dev$ echo "123" > globalmem   
  3. jay@jay:/dev$ cat globalmem   
  4. cat: globalmem: Device or resource busy  
  5. jay@jay:/dev$ echo "123" > globalmem   
  6. bash: globalmem: Device or resource busy  
  7. jay@jay:/dev$   



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章