一、原子操作
原子整形操作API
函數 |
描述 |
ATOMIC_INIT(int i) |
定義原子變量的時候對其初始化。 |
int atomic_read(atomic_t *v) |
讀取 v 的值,並且返回。 |
void atomic_set(atomic_t *v, int i) |
向 v 寫入 i 值。 |
void atomic_add(int i, atomic_t *v) |
給 v 加上 i 值。 |
void atomic_sub(int i, atomic_t *v) |
從 v 減去 i 值。 |
void atomic_inc(atomic_t *v) |
給 v 加 1,也就是自增。 |
void atomic_dec(atomic_t *v) |
從 v 減 1,也就是自減 |
int atomic_dec_return(atomic_t *v) |
從 v 減 1,並且返回 v 的值。 |
int atomic_inc_return(atomic_t *v) |
給 v 加 1,並且返回 v 的值。 |
int atomic_sub_and_test(int i, atomic_t *v) |
從 v 減 i,如果結果爲 0 就返回真,否則返回假 |
int atomic_dec_and_test(atomic_t *v) |
從 v 減 1,如果結果爲 0 就返回真,否則返回假 |
int atomic_inc_and_test(atomic_t *v) |
給 v 加 1,如果結果爲 0 就返回真,否則返回假 |
int atomic_add_negative(int i, atomic_t *v) |
給 v 加 i,如果結果爲負就返回真,否則返回假 |
原子位操作API
函數 |
描述 |
void set_bit(int nr, void *p) |
將 p 地址的第 nr 位置 1。 |
void clear_bit(int nr,void *p) |
將 p 地址的第 nr 位清零。 |
void change_bit(int nr, void *p) |
將 p 地址的第 nr 位進行翻轉。 |
int test_bit(int nr, void *p) 獲取 p |
地址的第 nr 位的值。 |
int test_and_set_bit(int nr, void *p) |
將 p 地址的第 nr 位置 1,並且返回 nr 位原來的值。 |
int test_and_clear_bit(int nr, void *p) |
將 p 地址的第 nr 位清零,並且返回 nr 位原來的值。 |
int test_and_change_bit(int nr, void *p) |
將 p 地址的第 nr 位翻轉,並且返回 nr 位原來的 |
二、自旋鎖
使用注意如下:
- ①、因爲在等待自旋鎖的時候處於“自旋”狀態,因此鎖的持有時間不能太長,一定要短,否則的話會降低系統性能。如果臨界區比較大,運行時間比較長的話要選擇其他的併發處理方式,比如稍後要講的信號量和互斥體。
- ②、自旋鎖保護的臨界區內不能調用任何可能導致線程休眠的 API 函數,否則的話可能導致死鎖。
- ③、不能遞歸申請自旋鎖,因爲一旦通過遞歸的方式申請一個你正在持有的鎖,那麼你就必須“自旋”,等待鎖被釋放,然而你正處於“自旋”狀態,根本沒法釋放鎖。結果就是自己把自己鎖死了!
- ④、在編寫驅動程序的時候我們必須考慮到驅動的可移植性,因此不管你用的是單核的還是多核的 SOC,都將其當做多核 SOC 來編寫驅動程序。
基本自旋鎖API
函數 |
描述 |
DEFINE_SPINLOCK(spinlock_t lock) |
定義並初始化一個自選變量。 |
int spin_lock_init(spinlock_t *lock) |
初始化自旋鎖。 |
void spin_lock(spinlock_t *lock) |
獲取指定的自旋鎖,也叫做加鎖。 |
void spin_unlock(spinlock_t *lock) |
釋放指定的自旋鎖。 |
int spin_trylock(spinlock_t *lock) |
嘗試獲取指定的自旋鎖,如果沒有獲取到就返回 0 |
int spin_is_locked(spinlock_t *lock) |
檢查指定的自旋鎖是否被獲取,如果沒有被獲取就返回非 0,否則返回 0。 |
中斷自旋鎖API
函數 |
描述 |
void spin_lock_irq(spinlock_t *lock) |
禁止本地中斷,並獲取自旋鎖。 |
void spin_unlock_irq(spinlock_t *lock) |
激活本地中斷,並釋放自旋鎖。 |
void spin_lock_irqsave(spinlock_t *lock,unsigned long flags) |
保存中斷狀態,禁止本地中斷,並獲取自旋鎖。 |
void spin_unlock_irqrestore(spinlock_t*lock, unsigned long flags) |
將中斷狀態恢復到以前的狀態,並且激活本地中斷,釋放自旋鎖。 |
下半部自旋鎖API
函數 |
描述 |
void spin_lock_bh(spinlock_t *lock) |
關閉下半部,並獲取自旋鎖。 |
void spin_unlock_bh(spinlock_t *lock) |
打開下半部,並釋放自旋鎖。 |
三、信號量
使用信號量會提高處理器的使用效率,畢竟不用一直傻乎乎的在那裏“自旋”等待。但是,信號量的開銷要比自旋鎖大,因爲信號量使線程進入休眠狀態以後會切換線程,切換線程就會有開銷。
使用注意如下:
- ①、因爲信號量可以使等待資源線程進入休眠狀態,因此適用於那些佔用資源比較久的場合。
- ②、因此信號量不能用於中斷中,因爲信號量會引起休眠,中斷不能休眠。
- ③、如果共享資源的持有時間比較短,那就不適合使用信號量了,因爲頻繁的休眠、切換線程引起的開銷要遠大於信號量帶來的那點優勢。
信號量API
函數 |
描述 |
DEFINE_SEAMPHORE(name) |
定義一個信號量,並且設置信號量的值爲 1。 |
void sema_init(struct semaphore *sem, int val) |
初始化信號量 sem,設置信號量值爲 val。 |
void down(struct semaphore *sem) |
獲取信號量,因爲會導致休眠,因此不能在中斷中使用。 |
int down_trylock(struct semaphore *sem); |
嘗試獲取信號量,如果能獲取到信號量就獲取,並且返回 0。如果不能就返回非 0,並且不會進入休眠。 |
int down_interruptible(struct semaphore *sem) |
獲取信號量,和 down 類似,只是使用 down 進入休眠狀態的線程不能被信號打斷。而使用此函數進入休眠以後是可以被信號打斷的。 |
void up(struct semaphore *sem) |
釋放信號量 |
四、互斥體
使用注意如下:
- ①、 mutex 可以導致休眠,因此不能在中斷中使用 mutex,中斷中只能使用自旋鎖。
- ②、和信號量一樣, mutex 保護的臨界區可以調用引起阻塞的 API 函數。
- ③、因爲一次只有一個線程可以持有 mutex,因此,必須由 mutex 的持有者釋放 mutex。並且 mutex 不能遞歸上鎖和解鎖。
互斥體API
函數 |
描述 |
DEFINE_MUTEX(name) |
定義並初始化一個 mutex 變量。 |
void mutex_init(mutex *lock) |
初始化 mutex。 |
void mutex_lock(struct mutex *lock) |
獲取 mutex,也就是給 mutex 上鎖。如果獲取不到就進休眠。 |
void mutex_unlock(struct mutex *lock) |
釋放 mutex,也就給 mutex 解鎖。 |
int mutex_trylock(struct mutex *lock) |
嘗試獲取 mutex,如果成功就返回 1,如果失敗就返回 0。 |
int mutex_is_locked(struct mutex *lock) |
判斷 mutex 是否被獲取,如果是的話就返回1,否則返回 0。 |
int mutex_lock_interruptible(struct mutex *lock) |
使用此函數獲取信號量失敗進入休眠以後可以被信號打斷。 |