Linux设备驱动中的并发

1、Linux中的并发与竞争
Linux设备驱动中必须解决的一个问题:多进程对共享资源的并发问题,
多个进程对同一个设备的并发访问,势必会导致对该设备资源的竞争。
竞态发生的几种情况:
1)、对称多处理器的多个CPU;
2)、单CPU内进程与抢占它的进程;
2)、中断(硬中断、软中断、tasklet、底半部)与进程之间
并发的概念:
多个执行单元同时、并行被执行,而并发执行单元对共享资源(硬件资源、
和软件上的全局变量、静态变量等)的访问则很容易导致竞态。
互斥访问的概念:
一个执行单元在访问共享资源的时候,其他执行单元被禁止访问。
临界区的概念;
访问共享资源的代码区;
同步的概念:
两件事情之间有先后顺序之分;
异步的概念:
两件事情的发生没有任何关联;

2、Linux中常用的同步访问技术
主要有中断屏蔽、原子操作、自旋锁和信号量等,中断屏蔽会使得中断得不到响应,
从而导致性能变差,原子操作受限于CPU,只能实现有限几种基本数据类型。
正确使用锁定机制的关键是,明确指定需要保护的资源,并确保每一个对资源的访问
使用正确的锁定。

 2.1中断屏蔽
中断屏蔽使得中断与进程之间的并发不再发生;
由于Linux内核的进程调度等操作都依赖中断来实现,内核抢占进程之间的
并发也就得以避免,它适合与自旋锁联合使用。
	local_irq_disable() //屏蔽中断
	...
	critical section  //临界区
	...
	local_irq_enable() //开中断

 2.2原子操作
原子操作函数主要有对位和整型变量进行操作。他们的共同点是在任何情况下
操作都是原子的,内核代码可以安全地调用它们而不会被打断。
	#define atomic_set(v, i) (((v)->counter) = (i))	//设定原子变量的值为i
	* atomic_set - set atomic variable
	* @v: pointer of type atomic_t
	* @i: required value
	
	atomic_t v = ATOMIC_INIT(0) //定义原子变量v并初始化为0
	
	#define atomic_read(v)	(*(volatile int *)&(v)->counter) //获取原子变量的值
	* atomic_set - set atomic variable
	* @v: pointer of type atomic_t
	* @i: required value
	
	static inline void atomic_add(int i, atomic_t *v) //原子变量增加i
{
	atomic_add_return(i, v);
}


static inline void atomic_sub(int i, atomic_t *v) //原子变量减少i
{
	atomic_sub_return(i, v);
}

2.3自旋锁
自旋锁不会进行休眠,而是在“原地打转”,它可在不能休眠的代码中使用,比如
中断处理例程,在正确使用的情况下,自旋锁通常可以提供比信号量更高的性能。
所以自旋锁等待在本质上都是不可中断的,一旦调用了spin_lock,在获得锁之前将一直
处于自旋的状态。任何拥有自旋锁的代码都必须是原子的,它不能休眠。
	spinlock_t spin;  //定义自旋锁
	spin_lock_init(&lock); //自旋锁初始化
	spin_lock(&lock); //获得自旋锁,保护临界区
	...
	critical section  //临界区
	...
	spin_unlock   //解锁

2.4信号量
当获取不到信号量时,进程不会原地打转而是进入休眠等待状态。信号量是进程
级的,用于进程间对资源的互斥。应该要在xxx_setup_cdev之前调用init_UTEX
	
	//初始化信号量
	sema_init(struct semaphore *sem);
	
	//获取信号量
	void down(struct semaphore *sem)
	* down - acquire the semaphore
	* @sem: the semaphore to be acquired
	
	int down_interruptible(struct semaphore *sem)
	* down_interruptible - acquire the semaphore unless interrupted
	* @sem: the semaphore to be acquired
以上两个函数的区别是,因为down()而进入休眠状态的进程不能被信号打断,
而因为down_interruptible()进入休眠的进程能被信号打断,信号也会导致该函
数的返回,以响应系统的某些变化。
	//使用信号量实现设备只能被一个进程打开
	static DECLEAR_MUTEX(xxx_lock);  //定义互斥锁
	
	static int xxx_open(struct inode *inode, struct file *filp)
	{
		....
		if (down_trylock(&xxx_lock)) //获得打开锁
			return -EBUSY;
		...
		return 0;
	}
	
	static int xxx_release(struct inode *inode, struct file *filp)
	{
		up(xxx_lock); //释放打开锁
		return 0;
	}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值