linux驅動開發(十一)linux內核信號量、互斥鎖、自旋鎖

參考: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,喚醒等待者。

 

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。

相關文章
相關標籤/搜索