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