一步一步走進字符驅動--自旋鎖
前面說到原子操作和今天的自旋鎖,以及信號量等.都是爲了防止搶佔式操作系統和SMP所帶來的競態的發生.那麼什麼叫競態呢?相信很多學過linux系統編程和window 開發的都知道.當一個進程在訪問一個公共資源時,由於時間片時間到或者被搶佔等,會導致其他進程運行,有可能也訪問該資源.那麼就會修改這份資源,導致本來的進程再此操作這份資源時,資源內的數據已被修改..由於這種情況,所以操作系統才引出各種鎖來鎖定公共資源來達到資源的保護.
今天我們大致看一下自旋鎖.
簡介:
自旋鎖是一種典型的對臨界區資源進行互斥訪問的手段,其名稱是根據它的工作方式得來的.爲了獲得自旋鎖,在某CPU上運行的代碼需先執行一個原子操作,該操作測試並設置某一內存變量,由於它是原子操作,所以在該操作完成之前其他執行單元不能訪問這個內存變量.如果測試結果表明鎖已經空閒,則程序獲得這個自旋鎖並繼續執行,如果測試表明鎖仍被佔用,程序將在一個小的循環內重複這個"測試並設置"操作,即進行所謂的"自旋",就是原子打轉.
自旋鎖定義: linux/Spinlock.h
typedef struct spinlock {
union {
struct raw_spinlock rlock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
#define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
struct {
u8 __padding[LOCK_PADSIZE];
struct lockdep_map dep_map;
};
#endif
};
} spinlock_t;
1:定義自旋鎖
spinlock_t lock;
2:初始化自旋鎖
spin_lock_init(lock); //該宏用於動態初始化自旋鎖
3:獲得自旋鎖
static inline void spin_lock(spinlock_t *lock); //獲取自旋鎖,若能獲取,則立即返回,否則自選在這等待獲取
static inline int spin_trylock(spinlock_t *lock); //嘗試獲取自旋鎖,若能獲取則返回TRUE,否則返回FALSE,不原地自選
4:釋放自旋鎖
static inline void spin_unlock(spinlock_t *lock); //釋放獲得的自旋鎖
示例:
/*定義一個自旋鎖*/
spinlock_t lock;
spin_lock_init(lock);
spin_lock(&lock); //獲取自旋鎖
/*臨界區資源*/
spin_unlock(&lock); //釋放自旋鎖
由於自旋鎖在自旋時不能被中斷打斷,否則將鎖死,所以延伸出帶中斷的自旋鎖
static inline void spin_lock_irq(spinlock_t *lock);
static inline void spin_unlock_irq(spinlock_t *lock);
#define spin_lock_irqsave(spinlock_t *lock, flags);
static inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
static inline void spin_lock_bh(spinlock_t *lock);
static inline void spin_unlock_bh(spinlock_t *lock);
自旋鎖主要針對單SMP和單CPU但支持搶佔式的情況,對於單CPU和內核不支持搶佔式的話,自旋鎖會退化成空操作.
自旋鎖實現設備打開唯一性,示例代碼:
spinlock_t lock;
int global_count = 0; //定義文件被打開的次數
int global_mem_open(struct inode *inode, struct file *filp)
{
/*將設備結構體指針賦給文件私有數據指針*/
struct globalmem_dev *devp;
devp = container_of(inode->i_cdev,struct globalmem_dev,cdev);
filp->private_data = devp;
spin_lock(&lock);
if (global_count) { //文件被打開
return -EBUSY;
}
global_count++;//增加使用計數器
spin_unlock(&lock);
/*判斷文件打開的標誌*/
return 0;
}
int global_mem_release(struct inode *inode, struct file *filp)
{
spin_lock(&lock);
global_count--;//減少使用計數器
spin_unlock(&lock);
return 0;
}