并发导致对共享资源的竞态
1、并发的来源
a、进程与中断处理路径之间的竞态
b、调度器可抢占性导致的同一个处理器上进程间的竞态
c、多处理器系统进程在不同处理器上并发执行导致的竞态(是严格意义上的并发)
2、对于单处理器,不可抢占式内核
主要的竞态是由进程和中断处理例程的对资源的竞争引起的。
可用local_irq_enable和local_irq_disable来解决。
local_irq_enable : 关闭本地处理器上的中断标志位,在进程进入临界区时关闭中断,防止在临界区代码执行过程中进程被中断,导致中断处理例程被中断的进程产生竞态
local_irq_disable : 开启本地处理器上的中断标志位,在离开临界区时调用
为了防止在一个中断关闭的环境中因为调用local_irq_disable local_irq_enable而把之前的中断响应状态破坏掉,所以在关中断前可将状态写入一个unsigned long flags中,在开中断后恢复之。
local_irq_save
local_irq_restore
3、多处理器系统
1)、暂不考虑a导致的竞态,并发的来源主要是b、c
在多处理器之间设置一个共享的自旋锁spinlogck_t V ,当V=1时上锁,V=0时解锁。
spin_lock : 上锁。i、通过preempt_disable关调度起的可抢占性。
ii、对自旋锁上锁。
spin_unlock :解锁。i、对自旋锁解锁。
ii、通过preempt_enable开来内核调度起的可抢占性。
2)、考虑a导致的并发
在1)的基础上加入对中断的控制
spin_lock_irq : 上锁。 i、通过local_irq_disable关本地中断
ii、通过preempt_disable关闭内核可抢占性
iii、对自旋锁上锁
spin_unlock_irq : 解锁。i、对自旋锁解锁
ii、通过local_irq_enable开本地中断
iii、通过preempt_enable打开内核抢占
3)、为防止上锁解锁前后中断状态的改变可以使用
spin_lock_irqsave
spin_unlock_irqrestore
4)、为了处理进程和软中断的竞态
spin_lock_bh
spin_unlock_bh
5)、以上函数是阻塞的,对应的非阻塞版本
阻塞版本 非阻塞版本
spin_lock spin_trylock
spin_lock_irq spin_trylock_irq
spin_lock_irqsave spin_trylock_irqsave
spin_lock_bh spin_trylock_bh
4、单处理器上的spin_lock函数
为了可移植性,在单处理起上也用上述函数。
5、读取者与写入者自旋锁rwlock
读写锁rwlock_t
1)对于读取者:
read_lock
read_rock_irq
read_lock_irqsave
read_unlock
read_unlock_irq
read_unlock_irqrestore
2)对于写入者
write_lock
write_lock_irq
write_lock_irqsave
write_unlock
write_unlock_irq
write_unlock_irqrestore
3)try版本
read_trylock
write_trylock
原则:
i、如果当前有进程在写,那么其他的进程就不能读,也不能写。
ii、如果当前进程在读,那么其他进程可以读,但是不能写。