- 自旋鎖概念
自旋鎖顧名思義首先是一把鎖,另外使用這把鎖的線程需要反覆自我循環(loop)檢測這把鎖是否可用。注意與信號量區別,信號量也是一把鎖,但是使用這把鎖的線程檢測鎖不可用時,選擇去睡眠,而不是自我循環。
自旋鎖與信號量相同點是兩者都是鎖,都具備鎖定特性,實現臨界區代碼塊的同步與互斥訪問。
- 自旋鎖注意事項
- 臨界區代碼不要存在睡眠情況(主要因爲發生睡眠不可預知睡眠多長時間,另外長時間睡眠,導致即將進入臨界區其他線程,長時間得不到自旋鎖,無休止自旋,從而導致死鎖),所以臨界區調用導致睡眠函數,不能選擇自旋鎖。
- 保證進入臨界區的線程,不發生內核搶佔。(這一點不必擔心,持有自旋鎖情況,Linux內核不進行搶佔)
- 臨界區代碼,執行時間不能太長。(因爲其他線程,如果要進入話,導致自旋,過多消耗CPU資源)
- 選擇自旋鎖時,也要注意中斷情況(上半部分中斷(硬件中斷)和下半部分中斷(軟中斷),中斷會搶佔即中斷到來時,打斷目前臨界區代碼執行,轉往執行中斷代碼),當中斷要進入自旋鎖保護臨界區代碼時,將導致線程與中斷髮生死鎖可能。
- 自旋鎖函數
1)自旋鎖頭文件
<linux/spinlock.h>
2)自旋鎖數據類型
spinlock_t
3)自旋鎖變量靜態(編譯時)初始化
spinlock_t lock = SPIN_LOCK_UNLOCKED;
4)自旋鎖變量動態(運行時)初始化
spinlock_t lock
spin_lock_init(&lock);
5)鎖定函數
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock); 禁止(屏蔽硬件中斷)自旋鎖,針對場合4情況
void spin_lock_bh(spinlock_t *lock);禁止(屏蔽下半部分中斷)自旋鎖,針對場合4情況
6)解鎖函數
void spin_unlock(spinlock_t *lock);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_unlock_irq(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);
- 讀寫自旋鎖
鎖的用途可以明確地分爲讀和寫。這種自旋鎖爲讀和寫分別提供了不同的鎖。一個或多少任務可以併發地持有讀取鎖;而寫入鎖一次最多隻能被一個任務持有,而且此時不能有併發的讀操作。我們可以將讀/寫鎖分別叫做共享(併發)/排斥鎖 。
讀寫自旋鎖相關函數
1)自旋鎖頭文件
<linux/rwlock.h>
2)自旋鎖數據類型
rwlock_t
3)自旋鎖變量靜態(編譯時)初始化
rwlock_t my_rwlock = RW_LOCK_UNLOCKED;
4)自旋鎖變量動態(運行時)初始化
rwlock_t my_rwlock;
rwlock_init(&my_rwlock);
5)讀鎖定函數
void read_lock(rwlock_t* lock);
void read_lock_irqsave(rwlock_t* lock, unsigned long flags);
void read_lock_irq(rwlock_t* lock);//禁止(屏蔽硬件中斷)自旋鎖,針對場合4情況
void read_lock_bh(rwlock_t* lock);//禁止(屏蔽下半部分中斷)自旋鎖,針對場合4情況
6)讀解鎖函數
void read_unlock(rwlock_t* lock);
void read_unlock_irqrestore(rwlock_t* lock, unsigned long flags);
void read_unlock_irq(rwlock_t* lock);
void read_unlock_bh(rwlock_t* lock);
6)寫鎖定函數
void write_lock(rwlock_t* lock);
void write_lock_irqsave(rwlock_t* lock, unsigned long flags);
void write_lock_irq(rwlock_t* lock);
void write_lock_bh(rwlock_t* lock);
void write_trylock(rwlock_t* lock);//嘗試獲得寫自旋鎖,不管是否成功,都會立即返回;
6)寫解鎖函數
void write_unlock(rwlock_t* lock);
void write_unlock_irqsave(rwlock_t* lock, unsigned long flags);
void write_unlock_irq(rwlock_t* lock);
void write_unlock_bh(rwlock_t* lock);
參考:http://blog.csdn.net/zhuriyuxiao/article/details/7641540
http://bdxnote.blog.163.com/blog/static/844423520124268101627/