併發與競態

1 中斷屏蔽

#include <linux/irqflags.h>
local_irq_disable();
local_irq_enable();
local_irq_save(flags);
local_irq_restore(flags);

2 原子操作

#include <asm/atomic.h>
atomic_t v;
//講原子變量的值初始化爲i
v=ATOMIC_INIT(i);
atomic_set(&v, i);

atomic_read(v);//讀取原子變量的值
void atomic_add(int i, atomic_t *v);
void atomic_sub(int i, atomic_t *v);
void atomic_inc(atomic_t *v);
void atomic_dec(atomic_t *v);
atomic_sub_and_test(i, v);
atomic_dec_and_test(v);
atomic_inc_and_test(v);
atomic_dec_return(v);
atomic_inc_return(v);
 int atomic_add_negative(int i, atomic_t *v)

3 自旋鎖

自旋鎖在獲取鎖之前一直進入忙循環並重複檢查鎖是否被解鎖,可用於不能休眠的流程中,例如中斷處理等。
擁有自旋鎖時禁止中斷;
自旋鎖擁有時間儘可能短;
自旋鎖下的執行函數不能休眠;
1.普通自旋鎖
#include <linux/spinlock.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
spinlock_t  lock=SPIN_LOCK_UNLOCK;
#else
DEFINE_SPINLOCK(lock);
#endif

spin_lock_init(&lock);

void spin_lock(&lock);
void  spin_lock_bh(&lock);//獲取自旋鎖之前禁止軟件中斷,但硬件中斷保持打開
void spin_lock_irq(&lock);//獲取自旋鎖之前禁止中斷
spin_lock_irqsave(&lock, flags);//獲取自旋鎖之前禁止中斷,並將之前的中斷狀態保存在flags中

void spin_unlock(&lock);
void spin_unlock_bh(&lock);//釋放自旋鎖,並恢復軟件中斷
void spin_unlock_irq(&lock);//釋放自旋鎖,並打開中斷
void spin_unlock_irqrestore(&lock, flags);//釋放自旋鎖,並將之前的中斷狀態恢復後打開中斷

非阻塞自旋鎖獲取:
成功返回非零值,否則返回零
int spin_trylock(&lock);
int spin_trylock_bh(&lock);
int spin_trylock_irq(&lock);

2.讀寫自旋鎖
#include <linux/rwlock.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
rwlock_t lock=RW_LOCK_UNLOCK;
#else
DEFINE_RWLOCK(lock);
#endif

rwlock_init(&lock);

read_lock(&lock);
read_lock_bh(&lock);//獲取自旋鎖之前禁止軟件中斷,但硬件中斷保持打開
read_lock_irq(&lock);//獲取自旋鎖之前禁止中斷
read_lock_irqsave(&lock, flags);//獲取自旋鎖之前禁止中斷,並將之前的中斷狀態保存在flags中

read_unlock(&lock);
read_unlock_bh(&lock);//釋放自旋鎖,並恢復軟件中斷
read_unlock_irq(&lock);//釋放自旋鎖,並打開中斷
read_unlock_irqrestore(&lock, flags);//釋放自旋鎖,並將之前的中斷狀態恢復後打開中斷

write_lock(&lock);
write_lock_bh(&lock);//獲取自旋鎖之前禁止軟件中斷,但硬件中斷保持打開
write_lock_irq(&lock);//獲取自旋鎖之前禁止中斷
write_lock_irqsave(&lock, flags);//獲取自旋鎖之前禁止中斷,並將之前的中斷狀態保存在flags中

write_unlock(&lock);
write_unlock_bh(&lock);//釋放自旋鎖,並恢復軟件中斷
write_unlock_irq(&lock);//釋放自旋鎖,並打開中斷
write_unlock_irqrestore(&lock, flags);//釋放自旋鎖,並將之前的中斷狀態恢復後打開中斷

非阻塞自旋鎖獲取:
成功返回非零值,否則返回零
read_trylock(&lock);
read_unlock_irqrestore(&lock, flags);
write_trylock(&lock);

4 信號量

信號量在獲取過程中會休眠,所以不能用於不能休眠的流程中,例如中斷處理等。
1.普通信號量
#include <asm/semaphore.h>
struct semaphore sem;
初始化方式一:
void sema_init(&sem,val);
初始化方式二:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
DECLARE_MUTEX(sem);
#else
DEFINE_SEMAPHORE(sem);
#endif
初始化方式三:
//在2.6.25後該函數已被廢除。請用sema_init(&sem,1);替代
void init_MUTEX(&sem);
void init_MUTEX_LOCKED(&sem);

void down(&sem);//獲取信號量
int down_interruptible(&sem);//獲取信號量,可被中斷
int down_trylock(&sem);//獲取信號量,永不休眠
void up(&sem);釋放信號量
2.讀寫信號量
#include <linux/rwsem.h>
struct rw_semaphore rw_sem;
void init_rwsem(&rw_sem);

void down_read(&rw_sem);//獲取信號量
int down_read_trylock(&rw_sem);//獲取信號量,永不休眠
void up_read(&rw_sem);釋放信號量

void down_write(&rw_sem);//獲取信號量
int down_write_trylock(&rw_sem);//獲取信號量,永不休眠
void up_write(&rw_sem);釋放信號量
void downgrade_write(&rw_sem);

5 互斥體

互斥體的使用方法和場景與信號量完全一樣。
#include <linux/mutex.h>
struct mutex mux;
mutex_init(mutex);

void mutex_lock(struct mutex *lock);
int __must_check mutex_lock_interruptible(struct mutex *lock);
int mutex_trylock(struct mutex *lock);

void mutex_unlock(struct mutex *lock);

6 completion

常用於進程、線程間同步
#include <linux/completion.h>
//不用聲明,詳細請查看頭文件定義
DECLARE_COMPLETION(comp);
//動態創建和初始化
struct completion comp;
void init_completion(&comp);
//等待完成
void wait_for_completion(&comp);
//觸發完成
void complete(&comp);
void complete_all(&comp);

7 位操作

//定義:include/asm-generic/bitops/atomic.h
#include <asm/bitops.h>
//設置addr地址的第nr位
void set_bit(int nr, volatile unsigned long *addr);
//清除addr地址的第nr位
void clear_bit(int nr, volatile unsigned long *addr);
//切換addr地址的第nr位
void change_bit(int nr, volatile unsigned long *addr);
//設置addr地址的第nr位並返回這個位的先前值
int test_and_set_bit(int nr, volatile unsigned long *addr);
//清除addr地址的第nr位並返回這個位的先前值
int test_and_clear_bit(int nr, volatile unsigned long *addr);
//切換addr地址的第nr位並返回這個位的先前值
int test_and_change_bit(int nr, volatile unsigned long *addr);

8 seqlock

#include <linux/seqlock.h>
DEFINE_SEQLOCK(lock);
seqlock_init(lock);
//用於獲取seqlock保護的資源的讀取訪問函數
unsigned read_seqbegin(const seqlock_t *sl);
//用於獲取seqlock保護的資源的寫入訪問函數
void write_seqlock(seqlock_t *sl);
//用於釋放seqlock保護的資源的寫入訪問函數
void write_sequnlock(seqlock_t *sl);
以上的讀寫函數還有很多變種,需要的請查看include/linux/seqlock.h文件

9 RCU(讀取-複製-更新)

#include <linux/rcupdate.h>
void rcu_read_unlock(void);
void rcu_read_lock(void);
void call_rcu(struct rcu_head *head,void (*func)(struct rcu_head *head));
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章