arm驱动linux并发与竞态并发控制
a)声明一个spinlock_t 变量lock
spinlock_t lock;
b)初始化spinlock_t 变量lock
有两种初始化方式:宏初始化与函数初始化
1)宏初始化方法SPIN_LOCK_UNLOCKED
spinlock_t lock = SPIN_LOCK_UNLOCKED;
2)函数初始化方法spin_lock_init(lock)
spin_lock_init(lock)
内核源码五)spin_lock_init的内核源码
//内核源码spin_lock_init发现使用SPIN_LOCK_UNLOCKED
#define spin_lock_init(lock) do{ *(lock) = SPIN_LOCK_UNLOCKED; } while(0)
c)获得自旋锁
1、获得自旋锁,spin_lock(lock) ;如果成功,立即获得锁,并马上返回,否则它将一直自旋在那里,直到该自旋锁的保持者释放。
spin_lock(lock)
//获取自旋锁lock,如果成功,立即获得锁,并马上返回,否则它将一直自旋在那里,直到该自旋锁的保持者释放。
内核源码六)spin_lock(lock)内核源码分析
//源码内核(可以看出来spin_lock没有获取锁,它将一直做while循环)
spin_lock(lock) _spin_lock(lock)
#define _spin_lock(lock) __LOCK(lock)
#define __LOCK(lock) do{ preempt_disable(); __acquire(lock); (void)(lock); } while(0)
#define preempt_disable() do{ } while(0)
//preempt_disable做空循环
2、试图获取自旋锁函数的spin_trylock(lock),如果能立即获得锁,并返回真,否则立即返回假。它不会一直等待被释放。(spin_trylock(lock)不做忙等待)
d)释放自旋锁lock,函数spin_unlock(lock) 它与spin_trylock或spin_lock配对使用。
3、自旋锁spinlock使用模板
模板四)自玄锁模板
spinlock_t lock;
spin_lock_init(&lock);
spin_lock(&lock);
spin_unlock(&lock);
Tip:将要保护的值(全局变量,静态变量,硬件资源)放在spin_lock(&lock)与spin_unlock(&lock)之间操作
spin_lock(&lock);
//改变要保护的全局变量或硬件资源或静态变量(共享变量)
spin_unlock(&lock);
4、特殊使用场景:有些设备只允许被打开一次,那么就需要一个自旋锁保护表示设备的打开和关闭状态的变量count。此处count属于临界资源,如果不对count进行保护,当设备打开频繁时,可能出现错误的count计数。
模板五)只允许被打开一次的设备驱动模板
intcount = 0;
spinlock_t lock;
intxxx_init(void){
//...其他代码..
spin_lock_init(&lock);
//...其他代码..
}
intxxx_open(structinode *inode, structfile *file){
spin_lock(&lock);//如果相同程序的进程要用open,那么其他进程就进入忙等到while(1)
if(count){
spin_unlock(&lock);
return-EBUSY;
}
count++;
spin_unlock(&lock);
//.....
}
intxxx_release(structinode *inode, structfile *file){
//....
spin_lock(&lock);//关闭时也要进行spin_lock保护,因为count是全局变量,要改变count就要加自旋锁
count--;
spin_unlock(&lock);
//.....
}
Tip:linux自旋锁和信号量所采用的"加锁(down)---访问临界区(critical section)---释放锁"的方式,被称为"互斥三部曲"。
五、总结:编写对共享资源(硬件资源和软件上的全局变量,静态变量等)的访问的驱动程序场景,就要考虑避免竞态的发生;避免方法:信号量(或说旗标,semaphore)机制与spin_lock机制(自旋锁)。
六、补充:信号量与自旋锁对比
信号量可能允许有多个持有者,而自旋锁在任何时候只能允许一个持有者。当然也有信号量叫互斥信号量(只能一个持有者),允许有多个持有者的信号量叫计数信号量。
信号量适合于保持时间较长的情况;而自旋锁适合于保持时间非常短的情况,在实际应用中自旋锁控制的代码只有几行,而持有自旋锁的时间也一般不会超过两次上下文切换的时间,因为线程一旦要进行切换,就至少花费切出切入两次,自旋锁的占用时间如果远远长于两次上下文切换,我们就应该选择信号量。
arm驱动linux并发竞态并发控 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)