程式扎記: [ Windows DDP ] 驅動程式的同步處理 : 自旋鎖

標籤

2011年1月19日 星期三

[ Windows DDP ] 驅動程式的同步處理 : 自旋鎖

前言 : 
自旋鎖也是一種同步處理機制, 它能保證某個資源只能被一個執行緒所擁有. 這種保護被形像的遞稱做 "上鎖", 本節主要對自旋鎖的原理和使用方法進行介紹. 

原理 : 
在 Windows 內核中, 有一種被稱為自旋鎖 (Spin Lock) 的鎖, 它可以用於驅動程式中的同步處理. 初始化自旋鎖時, 處於解鎖狀態, 這時它可以被程式 "獲取". "獲取" 後的自旋鎖處於鎖住狀態, 不能被再次 "獲取". 鎖住的自旋鎖必須被 "釋放" 以後, 才能再次被 "獲取". 
如果自旋鎖已經被鎖住, 這時有程式申請 "獲取" 這個自旋鎖, 程式則處於 "自旋" 狀態. 所位自旋狀態, 就是不停地詢問是否可以 "獲取" 自旋鎖. 自旋鎖也因此而得名. 
自旋鎖不同於執行緒中的等待事件. 在執行緒中如果等待某個事件 (Event), 作業系統會使這個執行緒進入休眠狀態, CPU 會執行其他執行緒. 而自旋鎖原理則不同, 它不會切換至別的執行緒, 而是一直讓這個執行緒 "自旋". 因此對自旋鎖佔用時間不宜過長, 否則會導致申請自旋鎖的其他執行緒處於自旋, 這會浪費寶貴的 CPU 執行時間. 
在單 CPU 的系統中, "獲取" 自旋鎖僅僅是將當前的 IRQL 從 PASSIVE_LEVEL 層級提升到 DISPATCH_LEVEL 層級. 但是在多 CPU 的系統中, 自旋鎖的實現方法會複雜得多. 有興趣的讀者可以針對自旋鎖的內核程式進行反組譯研究. 需要注意的是, 驅動程式必須在低於或者等於 DISPATCH_LEVEL 的 IRQL 層級中使用自旋鎖. 

使用方法 : 
自旋鎖的作用一般是為使各派遣函式之間同步, 盡量不要將自旋鎖放在全域變數, 而應該將自旋鎖放在裝置擴充裡. 自旋鎖用 KSPIN_LOCK 資料結構表示 : 

  1. typedef struct _DEVICE_EXTENSION {  
  2. ...  
  3.     KSPIN_LOCK My_SpinLock; // 再裝置擴充中定義自旋鎖  
  4. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;  
使用自旋鎖前, 需要先對其進行初始化, 可以使用 KeInitializeSpinLock . 一般在驅動程式的 DriverEntry 或者 AddDevice 函式中初始化自旋鎖. 申請自旋鎖可以使用內核函式KeAcquireSpinLock, 它有兩個參數, 第一個參數為自旋鎖指標, 第二個參數記錄獲得自旋鎖以前的 IRQL 層級. 一般用以下的方法初始化和申請獲得自旋鎖 : 
  1. PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;  
  2. KIRQL oldirql;  
  3. KeAcquireSpinLock(&pdx->My_SpinLock, oldirql);  
釋放自旋鎖使用 KeReleaseSpinLock 內核函式, 它也是兩個參數, 第一個為自旋鎖指標, 第二個是釋放自旋鎖後應該恢復的 IRQL 層級. 一般用下面方法是放自旋鎖 : 
KeReleaseSpinLock(&pdx->My_SpinLock, oldirql); 

如果在 DISPATCH_LEVEL 層級申請自旋鎖, 不會改變 IRQL 層級. 這時申請自旋鎖可以簡單地使用 KeAcquireSpinLockAtDpcLevel 內核函式, 而釋放自旋鎖使用KeReleaseSpinLockFromDpcLevel 內核函式.

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!