3.linux设备驱动中的并发控制

1.并发控制介绍
  • 并发会导致竞态的发生。 竞态: 一个资源被并发执行的任务同时访问时,就会出现竞争。此时的状态就是竞态。
  • 需保证一个资源在一个时间只能被一个任务访问,才能避免混乱。即并发控制
2.并发控制机制
2.1 互斥体

互斥体是专门用来做互斥的, 和二元的信号量类似,

	static struct mutex  lock;  /* 定义mutex */
	mutex_init(& lock);  /* 初始化mutex */
	
	mutex_lock(& lock);  /* 获取mutex */
	.../* 临界资源*/
	mutex_unlock(& lock); /* 释放mutex */
2.1 信号量

进程当中用于并发互斥和,资源的计数。
相对于自旋锁,信号量会睡眠,仅能用于进程中

#include <linux/semaphore.h>
static DEFINE_SEMAPHORE(demo_semlock);   //定义一个初始值为一的信号量
  
static int demo_open(struct inode *inode,struct file *file)
{            
	 if (down(&demo_semlock))  /* 获得打开锁*/
	 {
	    return  - EBUSY;  /* 设备忙*/
	 }
	 
	 printk("demo open \n");
	 return 0;
	}
	static int demo_release(struct inode *inode,struct file *file)
	{
	 up(&demo_semlock);  /* 释放打开锁*/
	 printk("demo release\n");
	 return 0;
	}	  
} 
2.3 自旋锁
  • cpu自旋死循环空转CPU 等待释放锁, 耗资源, 适用于锁持有时间小于睡眠唤醒时间场合

  • 进程递归获得锁时,会导致死锁

    static DEFINE_SPINLOCK(demo_spinlock); 
    static int hello_resource = 1;
    
    static int demo_open(struct inode *inode,struct file *file)
    {
      spin_lock(&demo_spinlock);  //还可和中断屏蔽合用 spin_lock_irq    
      if(demo_resource == 0)        //为避免死机, spin_try_lock
      {
         spin_unlock(&demo_spinlock); 
         return  - EBUSY; 
      }
      demo_resource--;
      spin_unlock(&demo_spinlock); 
    
    
      printk("demo open \n");
      return 0;
    } 
    static int demo_release(struct inode *inode,struct file *file)
    {
      spin_lock(&hello_spinlock);
      demo_resource++; 
      spin_unlock(&demo_spinlock);
    
      printk("demo release\n");
      return 0;
    }
    
2.4 原子操作

并发中不被打断的最小单元

#include <asm/atomic.h>
	  	
static atomic_t demo_atomic = ATOMIC_INIT(1);    //定义原子变量demo_atomic ,并初始化为1 
  static int demo_open(struct inode *inode,struct file *file)
  {			
	/*原子变量减1,并测试是否为零,为零返回真*/
    if (!atomic_dec_and_test(&demo_atomic))  {  
       atomic_inc(&demo_atomic);       	//原子变量加一,恢复自减前状态
       return  - EBUSY;   						//已经被打开
    }
    /*当第一次被open时, demo_atomic为1  , !atomic_dec_and_test 不成立, 正常打开*/
    printk("demo open \n");
    return 0;
  } 
  static int demo_release(struct inode *inode,struct file *file)
  { 
    atomic_inc(&demo_atomic);   //释放设备    
    printk("demo release\n");
    return 0;
  }
2.5 中断屏蔽

使用禁止中断方式,避免中断的影响

local_irq_disable       	//屏蔽中断
临界区代码              		//临界区: 访问共享资源的代码区域
local_irq_enable        	//开中断
 	 
注: 
1。屏蔽中断的时间尽量短,否则会造成别的中断延时过久,甚至丢失,最好能采有屏蔽指定中断的方式
  	disable_irq(int irq); //屏蔽指定中断号的中断
 	enable_irq(int irq);  //使能某中断号的中断   
2。常需保存当前的中断状态,便于恢复   
		用local_irq_save(flags);  代替local_irq_disable
		用local_irq_restore(flags) 代替 local_irq_enable
3 并发控制适用场合
  • 中断屏蔽的使用场合(中断和中断间,进程和中断竞争)
      当有中断处理程序访问共享资源的时候。
  • 原子操作的使用场合(进程间,中断间综合竞争。信号量、中断屏蔽等都是基于原子操作来实现)
      只使用于共享资源为一个变量的操作的情况
  • 自旋锁的使用场合(多CPU 竞争)
      多CPU的情况下
      在临界区代码运行时间比较短的情况。
  • 信号量互斥体的使用场合(进程间竞争,它不能防止中断的打断,故要防止中断打断,需与中断屏蔽混合使用)
      临界区代码运行时间比较长的情况。
      当锁持有的时间较长的时候,优先使用信号量。
      注意: 中断里不能使用信号量。 因为中断内不能睡眠。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值