操作系统中存在竞态问题,就是同时访问共享资源(包括程序,数据),引起竞态的原因有:smp,抢占式内核,中断(硬中断,软中断等).
抢占式内核竞态问题的图示:
假如代码如下:
write(resource);
write_count++;
A进程 B进程 C进程
------------------------------------------------------
写
------------------------------------------------------
写
-----------------------------------------------------
计数 =1
------------------------------------------------
读计数(这时,就有问题)
-----------------------------------------------------
计数=2
---------------------------------------------------
问题:进程c读计数时,实际写了两次,可是这里读计数只有1次,问题产生的原因就在于写和计数不是原子操作)。
保护共享资源的方法有:中断屏蔽,原子操作,锁,信号量.
1 中断屏蔽
变量
函数
local_irq_enable
local_irq_disable
用法
local_irq_disable
....
local_irq_enable
扩展:
local_irq_save(flags)
local_irq_restore(flags)
local_bh_enable
local_bh_disable
2原子操作
说明:原子操作,不会被打断
变量:
atomic_t
ATOMIT_INIT(i) 初始化值
函数
atomic_inc(atomic_t*)
atomic_dec(atomic_t*)
atomic_add(int,atomic_t*)
atomic_sub(int,atomic_t*)
atomic_read(atomic_t*)
atomic_inc_and_test(atomic_t*)
atomic_dec_and_test(atomic_t*)
atomic_sub_and_test(int,atomic_t*) 注意,没有加
atomic_inc_return(atomic_t*)
atomic_dec_return(atomic_t*)
atomic_add_return(int,atomic_t*)
atomic_sub_return(int,atomic_t*)
bit操作
set_bit(nr,void*)
clear_bit(nr,void*)
change_bit(nr,void*)
test_bit(nr,void*)
test_and_set(nr,void*) 先测试,再操作
test_and_clear(nr,void*)
test_and_change(nr,void*)
3 自旋锁
说明:
自旋锁会在原地打转,所以临界区尽可能短,不能阻塞.
变量:
spinlock_t lock
函数
spin_lock_init(spinlock_t*)
spin_lock(spinlock_t*)
spin_unlock(spinlock_t*)
用法
spinlock_t lock
spin_lock_init(&lock)
spin_lock(&lock)
...
spin_unlock(&lock)
扩展
spin_trylock(&lock)
spin_lock_irq(&lock)
spin_unlock_irq(&lock)
spin_lock_irqsave(&lock,flags)
spin_unlock_irqrestore(&lock,flags)
spin_lock_bh(&lock)
spin_unlock_bh(&lock)
读写自旋锁
说明:读写锁是比自旋锁粒度更小的锁,自旋锁对于读写不加区分,而实际上对于读操作是可以并发的,读写锁就是解决这个问题。当然,读和写也是不能同时进行的。
变量:
rwlock_t lock=RW_LOCK_UNLOCKED;静态初始化
函数
rwlock_init(rwlock_t*)动态初始化
read_lock(rwlock_t*)
read_unlock(rwlock_t*)
write_lock(rwlock_t*)
write_unlock(rwlock_t*)
用法
rwlock_t lock;
rwlock_init(&lock)
读自旋锁
read_lock(&lock)
...
read_unlock(&lock)
写自旋锁
write_lock(&lock)
...
write_unlock(&lock)
扩展
read_lock_irq(&lock)
read_unlock_irq(&lock)
read_lock_irqsave(&lock,flags)
read_unlock_irqrestore(&lock,flags)
read_lock_bh(&lock)
read_unlock_bh(&lock)
write_lock_irq(&lock)
write_unlock_irq(&lock)
write_lock_irqsave(&lock,flags)
write_unlock_irqrestore(&lock,flags)
write_lock_bh(&lock)
write_unlock_bh(&lock)
4 顺序锁
说明:顺序锁是读写锁的优化,读单元不会被写单元阻塞,写单元也不会被读单元阻塞。但是写单元之间仍然是互斥的。顺序锁有一个限制就是不能在其中使用指针,因为在保护的写单元中可能会使指针失效,而读单元此时使用指针就会失效。
变量:
seqlock_t lock;
函数:
write_seqlock(&lock)
write_sequnlock(&lock)
write_seqtrylock(&lock)
read_seqbegin(&lock)
read_seqretry(&lock,iv)
用法:
写操作
write_seqlock
...
write_sequnlock
读操作
do{
seqnum=read_seqbegin(&lock);
....
}while(read_seqretry(&lock,sequm))
扩展:
write_seqlock_irq(&lock)
write_sequnlock_irq(&lock)
write_seqlock_irqsave(&lock,falgs)
write_sequnlock_irqrestore(&lock,falgs)
write_seqlock_bh(&lock)
write_sequnlock_bh(&lock)
read_seqbegin_irqsave(&lock,falgs)
read_seqretry_irqrestore(&lock,iv,flags)
6 RCU
说明:rcu是read copy update的意思,可以看做是读写锁的高级版本,可以对保护单元同时进行读写.
变量:rcu_head head
函数:
read_lock_rcu()
read_unlock_rcu()
call_rcu(struct rcu_head*,void(*fun)(struct rcu_head*))
用法:
read_lock_rcu
...
read_unlock_rcu
扩展
list_add_rcu
list_add_tail_rcu
list_del_rcu
list_replace_rcu
list_for_each_rcu
list_for_each_safe_rcu
list_for_each_entry_rcu
hlist_add_head_rcu
hlist_del_rcu
hlist_for_each_rcu
hlost_for_each_entry_rcu
7 信号量
说明:
信号量与自旋锁不同,信号量会进入休眠状态,而自旋锁会在原地打转.
变量:
semaphore sem;
函数:
sema_init(struct semaphore *,int val)
DECLARE_MUTEX(name)
DECLARE_MUTEX_LOCKED(name)
init_MUTEX(&sem)
init_MUTEX_LOCKED(&sem)
down(&sem)
up(&sem)
用法:
down
....
up
扩展:
down_interruptible(&sem) 进入浅睡眠状态,可被打断.当调用此函数时需要检查其返回值如果返回非0,应当返回-ERESTARTSYS
down_trylock 尝试获得信号量,如果获得则立即返回0,否则返回非零值,此函数不会引起睡眠.
8 读写信号量
说明:
读写信号量与信号量的关系与读写锁与自旋锁的关系是一样的.
变量:
rw_semaphore sem
函数:
init_rwsem(&sem)
down_read
up_read
down_read_trylock
down_write
up_write
down_write_trylock
完成量
说明:
完成量是为了同步两个进程.
变量:
completion comp;
函数:
init_completion(&comp);
DECLARE_COMPLETION(name)
wait_for_completion
complete
complete_all
用法:
进程A 进程B
wait_for_completion complete
10 互斥体
说明:
互斥体与信号量是一样的.
变量:
mutex mux;
函数:
mutex_init(&mux)
mutex_lock
mutex_unlock
mutex_trylock
mutex_lock_interruptible
用法:
mutex_lock
...
mutex_unlock