參考:
http://www.360doc.com/content/12/0723/00/9298584_225900606.shtml
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html
http://blog.chinaunix.net/uid-25100840-id-3147086.html
http://blog.csdn.net/u012719256/article/details/52670098
-------------------------------------------------------------------------------------------------
在驅動程序中,當多個線程同時訪問相同的資源時(驅動程序中的全局變量是一種典型的共享資源),可能會引發"競態",因此我們必須對共享資源進行並發控制。Linux內核中解決並發控制的最常用方法是自旋鎖與信號量(絕大多數時候作為互斥鎖使用)。
自旋鎖與信號量"類似而不類",類似說的是它們功能上的相似性,"不類"指代它們在本質和實現機理上完全不一樣,不屬於一類。
自旋鎖不會引起調用者睡眠,如果自旋鎖已經被別的執行單元保持,調用者就一直循環查看是否該自旋鎖的保持者已經釋放了鎖,"自旋"就是"在原地打轉"。而信號量則引起調用者睡眠,它把進程從運行隊列上拖出去,除非獲得鎖。這就是它們的"不類"。
但是,無論是信號量,還是自旋鎖,在任何時刻,最多只能有一個保持者,即在任何時刻最多只能有一個執行單元獲得鎖。這就是它們的"類似"。
鑒於自旋鎖與信號量的上述特點,一般而言,自旋鎖適合於保持時間非常短的情況,它可以在任何上下文使用;信號量適合於保持時間較長的情況,會只能在進程上下文使用。如果被保護的共享資源只在進程上下文訪問,則可以以信號量來保護該共享資源,如果對共享資源的訪問時間非常短,自旋鎖也是好的選擇。但是,如果被保護的共享資源需要在中斷上下文訪問(包括底半部即中斷處理句柄和頂半部即軟中斷),就必須使用自旋鎖。
與信號量相關的API主要有:
定義信號量
一、信號量
信號量又稱為信號燈,它是用來協調不同進程間的數據對象的,而最主要的應用是共享內存方式的進程間通信。本質上,信號量是一個計數器,它用來記錄對某個資源(如共享內存)的存取狀況。一般說來,為了獲得共享資源,進程需要執行下列操作:
(1) 測試控制該資源的信號量。
(2) 若此信號量的值為正,則允許進行使用該資源。進程將信號量減1。
(3) 若此信號量為0,則該資源目前不可用,進程進入睡眠狀態,直至信號量值大於0,進程被喚醒,轉入步驟(1)。
(4) 當進程不再使用一個信號量控制的資源時,信號量值加1。如果此時有進程正在睡眠等待此信號量,則喚醒此進程。
維護信號量狀態的是Linux內核操作系統而不是用戶進程。我們可以從頭文件/usr/src/linux/include/linux/sem.h 中看到內核用來維護信號量狀態的各個結構的定義。信號量是一個數據集合,用戶可以單獨使用這一集合的每個元素。要調用的第一個函數是semget,用以獲得一個信號量ID。Linux2.6.26下定義的信號量結構體:
| struct semaphore sem; |

初始化信號量
| void sema_init (struct semaphore *sem, int val); |
該函數初始化信號量,並設置信號量sem的值為val
| void init_MUTEX (struct semaphore *sem); |
該函數用於初始化一個互斥鎖,即它把信號量sem的值設置為1,等同於sema_init (struct semaphore *sem, 1);
| void init_MUTEX_LOCKED (struct semaphore *sem); |
該函數也用於初始化一個互斥鎖,但它把信號量sem的值設置為0,等同於sema_init (struct semaphore *sem, 0);
獲得信號量
| void down(struct semaphore * sem); |
該函數用於獲得信號量sem,它會導致睡眠(這個睡眠和下面所說的不知道有什么不同,既然不能被其它地方喚醒,那么這個down有什么用呢?),因此不能在中斷上下文使用;
| int down_interruptible(struct semaphore * sem); |
該函數功能與down類似,不同之處為,down不能被信號打斷,但down_interruptible能被信號打斷;(這個能被信號打斷,有點疑惑,我現在做的項目是使用的是被中斷打斷,不知道它這個地方所說的是什么意思)
| int down_trylock(struct semaphore * sem); |
該函數嘗試獲得信號量sem,如果能夠立刻獲得,它就獲得該信號量並返回0,否則,返回非0值。它不會導致調用者睡眠,可以在中斷上下文使用。
釋放信號量
| void up(struct semaphore * sem); |
該函數釋放信號量sem,喚醒等待者。
2.互斥鎖
2.1概念
互斥體實現了“互相排斥”(mutual exclusion)同步的簡單形式(所以名為互斥體(mutex))。互斥體禁止多個線程同時進入受保護的代碼“臨界區”(critical section)。因此,在任意時刻,只有一個線程被允許進入這樣的代碼保護區。mutex實際上是count=1情況下的semaphore。
1 // 結構
2 struct mutex { 3 /* 1: unlocked, 0: locked, negative: locked, possible waiters */
4 atomic_t count; 5 spinlock_t wait_lock; 6 struct list_head wait_list; 7 #ifdef CONFIG_DEBUG_MUTEXES 8 struct thread_info *owner; 9 const char *name; 10 void *magic; 11 #endif
12 #ifdef CONFIG_DEBUG_LOCK_ALLOC 13 struct lockdep_map dep_map; 14 #endif
15 };
1 // 定義互斥鎖lock
2 mutex_init(struct mutex* lock)
或者直接用 #define DEFINE_MUTEX(LOCK)即可; 3
4 // 獲取
5 mutex_lock(struct mutex *lock) 6
7 // 釋放
8 mutex_unlock(struct mutex *lock)
struct mutex lock;
mutex_init(&lock);初始化互斥鎖
或者直接用 #define DEFINE_MUTEX(LOCK)即可;
#define __MUTEX_INITIALIZER(lockname) \ { .count = ATOMIC_INIT(1) \ , .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \ , .wait_list = LIST_HEAD_INIT(lockname.wait_list) \ __DEBUG_MUTEX_INITIALIZER(lockname) \ __DEP_MAP_MUTEX_INITIALIZER(lockname) } #define DEFINE_MUTEX(mutexname) \ struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) extern void __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key);
三:與自旋鎖相關的API主要有:
定義自旋鎖
| spinlock_t spin; |
初始化自旋鎖
| spin_lock_init(lock) |
該宏用於動態初始化自旋鎖lock
獲得自旋鎖
| spin_lock(lock) |
該宏用於獲得自旋鎖lock,如果能夠立即獲得鎖,它就馬上返回,否則,它將自旋在那里,直到該自旋鎖的保持者釋放;
| spin_trylock(lock) |
該宏嘗試獲得自旋鎖lock,如果能立即獲得鎖,它獲得鎖並返回真,否則立即返回假,實際上不再"在原地打轉";
釋放自旋鎖
| spin_unlock(lock) |
該宏釋放自旋鎖lock,它與spin_trylock或spin_lock配對使用;
除此之外,還有一組自旋鎖使用於中斷情況下的API。
