自旋鎖它是爲爲實現保護共享資源而提出一種鎖機制。其實,自旋鎖與互斥鎖比較類似,它們都是爲了解決對某項資源的互斥使用。無論是互斥鎖,還是自旋鎖,在任何時刻,最多隻能有一個保持者,也就說,在任何時刻最多隻能有一個執行單元獲得鎖。但是兩者在調度機制上略有不同。對於互斥鎖,如果資源已經被佔用,資源申請者只能進入睡眠狀態。但是自旋鎖不會引起調用者睡眠,如果自旋鎖已經被別的執行單元保持,調用者就一直循環在那裏看是否該自旋鎖的保持者已經釋放了鎖,"自旋"一詞就是因此而得名。
2 自旋鎖適用情況
自旋鎖比較適用於鎖使用者保持鎖時間比較短的情況。正是由於自旋鎖使用者一般保持鎖時間非常短,因此選擇自旋而不是睡眠是非常必要的,自旋鎖的效率遠高於互斥鎖。信號量和讀寫信號量適合於保持時間較長的情況,它們會導致調用者睡眠,因此只能在進程上下文使用,而自旋鎖適合於保持時間非常短的情況,它可以在任何上下文使用。如果被保護的共享資源只在進程上下文訪問,使用信號量保護該共享資源非常合適,如果對共享資源的訪問時間非常短,自旋鎖也可以。但是如果被保護的共享資源需要在中斷上下文訪問(包括底半部即中斷處理句柄和頂半部即軟中斷),就必須使用自旋鎖。自旋鎖保持期間是搶佔失效的,而信號量和讀寫信號量保持期間是可以被搶佔的。自旋鎖只有在內核可搶佔或SMP(多處理器)的情況下才真正需要,在單CPU且不可搶佔的內核下,自旋鎖的所有操作都是空操作。另外格外注意一點:自旋鎖不能遞歸使用。
3 自旋鎖 使用
自旋鎖定義: linux/Spinlock.h
在Linux中,每個自旋鎖都用spinlock_t結構表示:
typedef struct {
raw_spinlock_t raw_lock;
#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned int magic,
owner_cpu;
void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} spinlock_t;
typedef struct{
volatile unsigned int slock;
} raw_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_irq(spinlock_t *lock); //禁止本地中斷獲取指定的鎖
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags); //保存本地中斷的狀態,禁止本地中斷,並獲取指定的鎖
void spin_lock_bh(spinlock_t *lock) //安全地避免死鎖, 而仍然允許硬件中斷被服務
//釋放一個自旋鎖函數
void spin_unlock(spinlock_t *lock); //釋放指定的鎖
void spin_unlock_irq(spinlock_t *lock); //釋放指定的鎖,並激活本地中斷
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags); //釋放指定的鎖,並讓本地中斷恢復到以前的狀態
void spin_unlock_bh(spinlock_t *lock); //對應於spin_lock_bh
//非阻塞鎖
int spin_trylock(spinlock_t *lock); //試圖獲得某個特定的自旋鎖,如果該鎖已經被爭用,該方法會立刻返回一個非0值,
//而不會自旋等待鎖被釋放,如果成果獲得了這個鎖,那麼就返回0.
//而不會自旋等待鎖被釋放,如果成果獲得了這個鎖,那麼就返回0.
int spin_trylock_bh(spinlock_t *lock);
//這些函數成功時返回非零( 獲得了鎖 ), 否則 0. 沒有"try"版本來禁止中斷.
//其他
int spin_is_locked(spinlock_t *lock); //和try_lock()差不多,如果自旋鎖被置爲1(未鎖),返回0;否則,返回1
zz總結