自旋鎖:是linux核心中最常見的鎖,自旋鎖最多隻能被一個可執行線程持有,如果一個執行線程試圖獲得一個被持有的自旋鎖,那麼該線程會一直進行忙迴圈,旋轉,等待鎖重新可用.
在任何時候,自旋鎖都可以防止多於一個的執行線程同時進入臨界區,一個被爭用的自旋鎖會導致請求他的線程在等待鎖重新可用時自旋,所以自旋鎖不應被長期持有.這也是自旋鎖的初衷:在短期內進行輕量級加鎖.
自旋鎖的實現與體繫結構密切相關,代碼往往通過彙編實現.這些與體繫結構相關的代碼定義在<asm/spinlock.h>檔案中,實際會使用到的介面是<linux/spinlock.h>檔案中,自旋鎖的基本使用形式是:
spinlock_t mr_lock = SPIN_LOCK_UNLOCKED;
spin_lock(&mr_lock);
/*
臨界區
*/
spin_unlock(&mr_lock);
因為自旋鎖同一時刻最多隻能被一個執行線程持有,所以同一個時刻只會有一個線程處於臨界區內,這就為多處理器提供了防止並發訪問所需要的保護機制.
自旋鎖也可以用在中斷處理常式中,在中斷處理常式使用自旋鎖之前,一定要先進位本地中斷,否則,中斷處理常式就會打斷正持有鎖的核心代碼,有可能會去爭用這個被持有的自旋鎖,但是鎖的持有人在這個中斷處理常式結束之前不能運行,從而造成了死結.
核心提供的進位中斷同時請求鎖的介面:
spinlock_t mr_lock = SPIN_LOCK_UNLOCKED;
unsigned long flags;
spin_lock_irqsave(&mr_lock,flags);
/*
臨界區
*/
spin_lock_irqrestore(&mr_lock,flags);
解釋:
spin_lock_irqsave()儲存中斷的目前狀態,並禁止本地中斷,然後再去獲得指定的鎖,而spin_lock_irqrestore()是對指定的鎖解鎖,並讓她恢複到加鎖前的狀態.
針對自旋鎖的操作:
spin_lock_init()用來初始化動態建立的自旋鎖,此時你只有一個指向spinlock_t類型的指標,並沒有它的實體.
spin_try_lock()試圖獲得某個特定的自旋鎖,如果該鎖已經被爭用,該方法會立刻返回一個非0值,而不會自旋等待鎖被釋放,如果成果獲得了這個鎖,那麼就返回0.
spin_is_locked()方法和spin_try_lock()是一樣的功效,該方法只做判斷,並不生效.
spin_lock();//擷取指定的自旋鎖
spin_lock_irq();//禁止本地中斷擷取指定的鎖
spin_lock_irqsave();//儲存本地中斷的狀態,禁止本地中斷,並擷取指定的鎖
spin_unlock();//釋放指定的鎖
spin_unlock_irq();//釋放指定的鎖,並啟用本地中斷
spin_unlock_irqrestore();//釋放指定的鎖,並讓本地中斷恢複到以前的狀態
spin_lock_init();//初始化指定的spinlock_t
spin_try_lock();//試圖擷取指定的鎖,如果未擷取,則返回非0
spin_is_locked();//和try_lock()差不多
有很多時候鎖的用途可以明確的分為讀取和寫入,比如說讀寫鏈表,因此linux就專門的提供了讀-寫自旋鎖,這種鎖為讀和寫分別提供了不同的鎖:一個或多個讀任務可以並發的持有讀者鎖,相反用於寫的鎖最多隻能被一個寫任務持有,而且此時不能有並發的讀操作.
讀/寫自旋鎖的使用方法類似於普通自旋鎖,它們通過下面的方法初始化,具體的方法就不詳細述說了.
需要注意的兩點:自旋鎖不能遞迴,防止死結的產生.