linux驅動程序開發3

驅動程序中的併發控制方法:

一個硬件可能會被多個進程併發使用,例如scull_read的時候被另外一個進程調用的scull_write打斷,那麼讀到的數據就不是以前應該讀到的數據,這就需要併發控制

併發控制其實多數是使用信號量來完成,包括如下5種方式:1 信號量,2自旋鎖,3讀寫信號量,4讀寫自旋鎖,5completion機制


信號量操作方法:

1 定義及初始化

struct semaphore sem;

可用void sema_init(struct semaphore *sem, int val);直接創建,其中val爲信號量初值。

也可以用兩個宏來定義和初始化信號量的值爲1或0:

DECLARE_MUTEX(name) : 定義信號量name並初始化爲1

DECLARE_MUTEX_LOCKED(name) : 定義信號量name並初始化爲0

還可以用下面的函數初始化:

void init_MUTEX(struct semaphore *sem); //初始化信號量的值爲1

void init_MUTEX_LOCKED(struct semaphore *sem); //初始化信號量的值爲0


2 信號量操作

p操作:

void down(struct semaphore *sem); //用來獲取信號量,如果信號量值大於或等於0,獲取信號量,否則進入睡眠狀態,睡眠狀態不可喚醒

void down_interruptible(struct semephore *sem); //用來獲取信號量,如果信號量大於或等於0,獲取信號量,否則進入睡眠狀態,等待信號量被釋放後,激活該程。

void down_trylock(struct semaphore *sem); //試圖獲取信號量,如果信號量已被其他進程獲取,則立刻返回非零值,調用者不會睡眠

v操作:

void up(struct semaphore *sem); //釋放信號量,並喚醒等待該資源進程隊列的第一個進程函數

3 使用方法

定義:struct semaphore sem;

初始化:sema_init(&sem, 1);

獲取信號量:if(down_interruptible(&sem))

                      return -ERESTARTSYS;

釋放信號量:up(&sem);


4注意事項

down爲深度睡眠,不能被信號中斷;淺度睡眠down_interruptible可以被信號中斷,返回值可以用於判斷被喚醒的原因是由於其他進程執行了up還是收到了信號。


5 實驗

在scull_read中加入:ssleep(5);

寫入數據:echo yang>./scull0

併發讀出數據:cat ./scull0 & cat ./scull0

查看驅動的輸出:tail /var/log/syslog


自旋鎖的編程實戰:

1 自旋鎖的特點及與信號量的區別

(1)自旋鎖是一個互斥設備,只有兩個值:上鎖,解鎖

(2)上鎖spin_lock進入臨界區以後,操作系統不能進行任務調度,只會響應中斷,且中斷結束後也不進行進程調度,而是回到持有自旋鎖的進程

(3)如果獲取自旋鎖的時候已經被上鎖,代碼會一直檢查這個鎖,持續佔用cpu,且不會進入休眠,導致佔用大量cpu資源,所以只適合臨界區代碼比較短的場合

(4)持有自旋鎖以後的進程不要進入休眠,否則無法釋放自旋鎖,導致系統死鎖。

2 自旋鎖的操作方法

(1)定義和初始化

spinlock_t my_lock=SPIN_LOCK_UNLOCKED;

void spin_lock_init(spinlock_t *lock);

(2)自旋鎖操作函數

void spin_lock(spinlock_t *lock)  //獲取鎖

void spin_unlock(spinlock_t *lock) //釋放鎖

其他函數

void spin_lock_irqsave(spinlock_t *lock, unsigned long flags)//禁止中斷,但是保存interrupt中的flag

void spin_lock_irq(spinlock_t *lock)//期間禁止中斷

void spin_lock_bh(spinlock_t *lock)//禁止軟件中斷,使能硬件中斷

int spin_trylock(spinlock_t *lock)

int spin_trylock_bh(spinlock_t *lock)


2 使用方法:

(1)定義

spinlock_t lock;

(2)初始化

spin_lock_init(&lock);

(3)獲取自旋鎖

spin_lock(&lock);

(4)釋放自旋鎖

spin_unlock(&lock);


3 讀寫自旋鎖

在控制讀和寫不能併發執行的前提下,使得多個讀可以併發執行聲明和初始化

rwlock_t my_rwlock=RW_LOCK_UNLOCKED;

rwlock_t my_rwlock;rwlock_init(&my_rwlock);

操作方法:

void read_lock(rwlock_t *lock)

void read_lock_irqsave(rwlock_t *lock, unsigned long flags)

void read_lock_irq(rwlock_t *lock)

void read_lock_bh(rwlock_t *lock)

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)



Competions機制

編寫驅動的時候,經常會做如下操作,在當前線程中初始化並啓動另外的線程,並且當前現成必須等待被啓動的夥伴線程幫助自己完成某些工作後,自己才能繼續執行

內核的信號量api針對可獲得的情況進行了專門的優化,當按照上述程序的方式來使用信號量api完成工作,則會導致第一個線程幾乎必然阻塞在down調用處,因此會導致性能遭受極大的下降

(1)定義,初始化

struct completion my_completion;

init_completion(&my_completion);

(2)等待完成量

void wait_for_completion(struct completion *c)

(3)喚醒完成量

void complete(struct completion *c)

void complete_all(struct completion *c)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章