天天看点

linux设备驱动中的并发控制——自旋锁

  1. int xxx_count = 0;//定义文件打开次数计数  
  2.        static int xxx_open(struct inode *inode,struct file *filp)  
  3.        {  
  4.         ...  
  5.         spinlock(&xxx_lock);  
  6.         if(xxx_count)//已打开  
  7.         {  
  8.             spin_unlock(&xxx_lock);  
  9.             return - EBUSY;  
  10.         }  
  11.         xxx_count++;//增加使用计数  
  12.         spin_unlock(&xxx_lock);  
  13.         ...  
  14.         return 0;//成功  
  15.         }  
  16.         static int xxx_release(struct inode *inode,struct file *filp)  
  17.         {  
  18.             ...  
  19.             spinlock(&xxx_lock);  
  20.             xxx_count--;//减少使用计数  
  21.             spin_unlock(&xxx_lock);  
  22.             return 0;//成功  
  23.         } 
  2 读写自旋锁      读写自旋锁是一种比自旋锁力度更小的锁机制,他保留了"自锁"的概念,但是在写方面,只能最多有一个写进程,在读方面,同时可以有多个读执 行单元,当然读写不能同时进行。   读写自旋锁的操作如下:   1)定义和初始化读写自旋锁   rwlock_t my_rwlock = RW_LOCK_UNLOCKED;//静态初始化   rwlock_t my_rwlock;   rwlock_init(&my_rwlock);//动态初始化   2)读锁定   void read_lock(rwlock_t *lock);   void read_lock_irqsave(rwlock_t *lock,unsigned long flags);   void read_lock_irq(rwlock_t *lock);   void read_lock_bh(rwlock_t *lock);   3)读解锁   void read_unlock(rwlock_t *lock);   void read_unlock_irqsave(rwlock_t *lock,unsigned long flags);   void read_unlock_irq(rwlock_t *lock);   void read_unlock_bh(rwlock_t *lock);   说明:在对共享资源进行读取之前,应该先调用读锁定函数,完成之后应调用解读锁定函数   4)写锁定   void write_lock(rwlock_t *lock);   void write_lock_irqsave(rwlock_t *lock,unsigned long flags);   void write_lock_irq(rwlock_t *lock);   void write_lock_bh(rwlock_t *lock);   void write_trylock(rwlock_t *lock);   5)写解锁   void write_unlock(rwlock_t *lock);   void write_unlock_irqsave(rwlock_t *lock,unsigned long flags);   void write_unlock_irq(rwlock_t *lock);   void write_unlock_bh(rwlock_t *lock);      说明:在对共享资源进行读取之前,应该先调用写锁定函数,完成之后应调用解写锁定函数    读写自旋锁的使用方法如下:    rwlock_t lock;//定义读写自旋锁    rwlock_init(&lock);//初始化    //读时获取锁    read_lock(&lock);    ...//临界资源    read_unlock(&lock);    //写时获取锁    write_lock_irqsave(&lock,flags);    ...//临界资源    write_unlock_irqrestore(&lock,flags); 3 顺序锁     顺序锁是对读写锁的一种优化,使用顺序锁,读执行单元不会被写执行单元堵塞。     linux内核中,写执行单元涉及如下顺序锁操作     1)获得顺序锁     void write_seqlock(seqlock_t *s1);     int write_tryseqlock(seqlock_t *s1);     write_seqlock_irqsave(lock,flags);     write_seqlock_irqe(lock);     write_seqlock_bh(lock);     2)释放顺序锁     void write_sequnlock(seqlock_t *s1);     write_sequnlock_irqrestore(lock,flags);     write_sequnlock_irqe(lock);     write_sequnlock_bh(lock);     //顺序锁的使用模式:     write_seqlock(&seqlock_a);     ...//写操作代码块     write_sequnlock(&seqlock_a);     读执行单元涉及如下操作:     1)读开始     unsigned read_seqbegin(const seqlock_t *s1);     read_seqbegin_irqsave(lock,flags)     2)重读     int read_seqretry(const seqlock_t *s1,unsigned iv);     read_seqretry_irqrestore(lock,iv,flags);     读执行单元访问顺序锁的模式如下:     do{            seqnum = read_seqbegin(&seqlock_a)             //读操作代码块                 ...        }while(read_seqretry(&seqlock_a,seqnum));  4 读-拷贝-更新(RCU)     RCU可以看做读写锁的高性能版本,相比读写锁,RCU的优点在于既允许多个读执行单元同时访问被保护的数据,又允许多个读执行单元和多个写执行单元同时访问被保护的数据。     但是,RCU不能代替读写锁,因为如果写比较多时,对读执行单元的性能提高不能弥补写执行单元导致的损失。因为使用RCU时,写执行单元之间的同步开销会比较大,它需要延迟数据结构的释放,复制被修改的数据结构,它也必须使用某种锁机制同步并行的其他写执行单元的修改操作。  linux系统提供如下4中RCU的操作   1)读锁定   rcu_read_lock()   rcu_read_lock_bh()   2)读解锁   rcu_read_unlock()   rcu_read_unlock_bh()  使用模式如下:   rcu_read_lock()   ...//读临界区   rcu_read_unlock()  实际上,rcu_read_lock(),rcu_read_unlock()实质上只是禁止和使能内核的抢占进度   3)同步RCU   synchronize_rcu()   该函数由RCU写执行单元调用,将阻塞写执行单元,直到所有读执行单元已经完成度执行单元临界区 ,写执行单元才可以继续下一步。   4)挂接回调   void fastcall call_rcu(struct rcu_head *head,void (*func)(struct rcu_head *rcu));      该函数也由RCU的写执行单元调用,他不会使写执行单元阻塞,因而可以在中断上下文或软中断中使用。该函数 将由函数func挂接到RCU回调函数链上,然后立即返回。

继续阅读