Linux设备驱动开发详解--笔记7--并发控制

来源:互联网 发布:剑灵动漫人物捏脸数据 编辑:程序博客网 时间:2024/05/29 10:48

中断屏蔽的使用方法:

local_irq_disable() //关中断

local_irq_enable() //开中断

 

这两个函数都只能禁止和使能本cpu内的中断,因此,并不能解决SMP多cpu引发的竞态。因此,单独使用中断屏蔽通常不是一种值得推荐的避免竞态的方法,它适宜与自旋锁联合使用

 

另外,local_irq_save(flags)除了进行禁止中断操作以外,还保存目前cpu的中断位信息,local_irq_restore(flags)相反

 

如果只想禁止中断的底半部,应该使用local_bh_disable(),相反local_bh_enable()

 

整型原子操作

1、设置原子变量的值

void atomic_set(atomic_t *v, int i); //设置原子变量的值为i

atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0

……

 

自旋锁:为了获得一个自旋锁,在某cpu上运行的代码首先需要执行一个原子操作,该操作测试并设置(test-and-set)某个内存变量,由于它是原子操作,所以在该操作完成之前其他执行单元不可能访问这个内存变量。如果测试结果表明已经空闲,则程序获得这个自旋锁并继续执行;如果被占用,程序将在一个小的循环内重复这个“test-and-set”操作,即进行所谓的“自旋”。一般这样使用自旋锁:

spinlock_t lock; //定义自旋锁

spin_lock_init(&lock); //初始化自旋锁

spin_lock(&lock); //获得自旋锁,保护临界区

spin_unlock(&lock); //解锁

 

自旋锁衍生体制:

 

注意:

1、只有在占用锁的时间极短的情况下,使用自旋锁才是合理的

2、自旋锁可能导致系统死锁,如递归使用自旋锁,即已经拥有cpu的进程想第二次获得。copy_from_user和copy_to_user()和kmalloc()等函数都可能引起阻塞,因此在自旋锁的占用期间不能调用这些函数

 

读写自旋锁(rwlock):是一种比自旋锁粒度更小的锁机制,保留了“自旋”的概念,同时只能一个写进程,同时可以有多个读执行单元,当然,读写不能同时进行

 

顺序锁(seqlock):度执行单元可以再写执行单元对被顺序锁保护的共享资源进行写操作时仍然可以继续读,而不必等待写执行单元完成写操作,写执行单元也不需要等待所有读执行单元完成读操作才去进行写操作。但是写与写之间还是互斥的

限制:要求被保护的共享资源不含有指针,因为写执行单元可能使得指针失效,但读执行单元如果正要访问该指针,将导致Oops

 

RCU(Read-Copy Update,读-拷贝-更新):对于被RCU保护的共享数据结构,读执行单元不需要获得任何锁就可以访问它,不使用原子指令。RCU可以看做是读写锁的高性能版本,优点在于既允许多个读执行单元同时访问被保护的数据,又允许多个读执行单元和多个写执行单元同时访问被保护数据。但是,RCU不能替代读写锁,因为如果写比较多时,对读写单元性能的提高不能弥补写单元导致的损失。因为使用RCU时,写执行单元之间的同步开销比较大

 

在中断中不能使用信号量

 

自旋锁最多只能被一个可执行线程持有,不会引起调用者睡眠,如果一个执行线程试图获得一个已经持有的自旋锁,那么线程会一直进行忙循环,一直等待下去,在那里看是否该自旋锁的保持者已经释放了锁

 

信号量适合于保持时间较长的情况,自旋锁适合于保持时间非常短的情况,在实际应用中自旋锁控制的代码只有几行,而持有自旋锁的时间一般不会超过两次上下文切换的时间,因为线程一旦要进行切换就至少花费切出切入两次,自旋锁的占用时间如果远长于两次上下文切换,我们应该选择信号量