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


參考:

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。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM