7、linux设备驱动--并发控制

 

1.并发与竞态

并发指的是多个执行单元同时、并行被执行,而并发的执行单元对共享资源(全局变量、静态变量)的访问容易导致竞态。

         

2.中断屏蔽                                                                            

      中断屏蔽使用方法:

                          local_irq_disable()  //屏蔽中断                                 

                             ……………        //临界区                                  

                          local_irq_enable()   //开中断   

       local_irq_disable()和local_irq_enable()只能禁止和全能本CPU内    

   的中断;local_irq_save(flags)除了进行禁止中断操作外,还保存目前CPU 

   中断位信息,local_irq_restore(flags)进行与local_irq_save(flags)相 

   反操作                                 

3.原子操作                                                                          

   原子操作指的是在执行过程中不会被别的代码路径所中断的操作

3.1 整形原子操作                                                                      

   1.设置原子变量的值                                                                 

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

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

   2.获取原子变量的值                                                                 

        atomic_read(atomic_t *v);    //返回原子变量的值                                      

   3.原子变量加/减                                                                    

        void atomic_add(int i , atomic_t *v);//原子变量增加i                               

        void atomic_sub(int i , atomic_t *v);//原子变量减少i                             

   4.原子变量自增/自减                                                          

        void atomic_inc(atomic_t *v);   //原子变量增加i                                        

        void atomic_dec(atomic_t *v);   //原子变量减少i                                        

   5.操作并测试

        int atomic_inc_and_test(atomic_t *v);    //自增并测试

        int atomic_dec_and_test(atomic_t *v);    //自减并测试

        int atomic_sub_and_test(int i , atomic_t *v); //减并测试

      上述是测试其是否为0,为0返回true,否则返回false

   6.操作并返回

        int atomic_add_return(int i , atomic_t *v);

        int atomic_sub_return(int i , atomic_t *v);

        int atomic_inc_return(int i , atomic_t *v);

        int atomic_dec_return(int i , atomic_t *v);

      上述操作对原子变量进行加/减和自增/减操作,并返回新的值

3.2 位原子操作

   1.设置位

        void set_bit(nr , void *addr);

   2.清除位

        void clear_bit(nr , void *addr);

     上述操作清除addr地址的第nr位,所谓清除位即是将位写为0

   3.改变位

        void change_bit(nr , void *addr);

     上述操作清除addr地址的第nr位进行反置

   4.测试位

        test_bit(nr , void *addr);

     上述操作返回addr地址的第n位

   5.测试并操作位

     int test_and_set_bit(nr , void *addr);                                                  

     int test_and_clear_bit(nr , void *addr);                                                

     int test_and_change_bit(nr , void *addr);                                            

     上述test_and_xxx_bit(nr , void *addr)操作等同于执行test_bit(nr ,                           

   void *addr)后再执行xxx_bit(nr , void *addr)                                        

4.自旋锁(spin lock)

    自旋锁是一种典型的对临界资源进行互斥访问的手段。理解自旋锁最简单的方法就是把它当作一个变量来看。

     Linux中与自旋锁相关的操作有4种:

       1.定义自旋锁

          spinlock_t lock;

       2.初始化自旋锁

          spin_lock_init(lock);   //用于动态初始化自旋锁

       3.获得自旋锁

          spin_lock(lock);和 spin_trylock(lock);

         前者如果立即获得锁,就马上返回,否则自旋在那;后者如果立即获 

       得锁,它获得锁并返回真,否则立即返回假,不在原地打转

       4.释放自旋锁

          spin_unlock(lock);//与spin_lock和spin_trylock配对使用

       5.自旋锁一般使用方法(*)

              spinlock_t lock;        

              spin_lock_init(&lock);

              spin_lock(&lock);      

               ...............    

              spin_unlock(&lock);   

       6. 自旋锁与中断的联合使用

           spin_lock_irq() = spin_lock() + local_irq_disable()

           spin_unlock_irq() = spin_unlock() + local_irq_enable()

           spin_lock_irqsave() = spin_lock() + local_irq_save()

           spin_lock_irqrestore() = spin_unlock() + local_irq_restore()

          spin_lock_irq()、spin_lock_irqsave()类似函数会为自旋锁的使用

       系好“安全带”以避免突入其来的中断驶入对系统的危害

5.信号量(semaphore)

5.1信号量的使用

   信号量(semaphore)是用于保护临界区的一种常用方法,与自旋锁相同的是:只有得到信号量的进程才能执行临界区代码;不同的是:当获取不到信号量时,进程不会原地打转而是进入休眠等待状态。

   Linux中与信号量相关的操作主要有:

      1.定义信号量

          struct semaphore sem; //定义名称为sem的信号量

      2.初始化信号量

          void sema_init(struct semaphore *sem , int val);//初始化信号               

                                      //量,并设置信号量sem的值为val

          #define init_MUTEX(sem)  sema_init(sem , 1) //初始化一个互斥          

                                    //的信号量,把信号量sem的值设为1

          #define init_MUTEX_LOCKED(sem)  sema_init(sem , 0)  //初始化 

                              //一个信号量,但它把信号量sem的值设为0

          定义并初始化信号量的快捷方式:

                DECLARE_MUTEX(name) 和DECLARE_MUTEX_LOCKED(name)

        前者定义一个名为name的信号量并初始化为1;后者定义一个名为      

        name的信号量并初始化为0

       3.获得信号量

           void down(struct semaphore *sem);//用于获得信号量sem,它会       

                               //导致睡眠,因此不能在上下文中断中使用

           int down_interruptiable(struct semaphore *sem);//类似down

         两者区别:down()而进入睡眠状态和进程不能被信号打断,但是         

                   down_interruptiable()而进入睡眠状态能被信号打断

           int down_trylock(struct semaphore *sem);//偿试获得信号量   

           //sem,如果立即获得,就获得该信号量并返回0,否则返回非0值

       4.释放信号量

           void up(struct semaphore *sem);//释放信号量,唤醒等待者

       

       5.信号量一般使用方法

          DECLARE_MUTEX(mount_sem); //定义信号量

          down(&mount_sem);        //获取信号量,保护临界区

           .............          //临界区

          up(&mount_sem);        //释放信号量

5.2信号量用于同步

    如果信号量初始化为0,则它可以用于同步,同步意味着一个执行单元的继续执行需等待另一执行单元完成某事,保证执行的先后顺序。

5.3自旋锁VS信号量

    自旋锁和信号量都是解决互斥问题的基本手段。信号量和自旋锁属于不同层次的互斥手段,前者的实现有赖于后者。

    1.信号量是进程级的,进程上下文切换的开销很大,因此只有当进程占用资   

      源时间较长时,用信号量才是较好选择。

    2.当所要保护的临界区访问时间比较短时,用自旋锁是非常方便的,因为它

      节省上下文切换的时间,但CPU得不到自旋锁会在原地打转,所以要求锁

      不能在临界区长时间停留,否则会降低系统的效率。

    3.信号量所保护的临界区可包含可能引起阻塞的代码,而自旋锁则绝对要避

      免用来保护包含这样代码的临界区。因为阻塞意味着要进行进程切换,如

      果进程被切换出去后,另一个进程企图获取本自旋锁,死锁就会发生。

6.互斥体

  定义名为my_mutex的互斥体并初始化:

                struct mutex my_mutex;   //定义互斥体

                mutex_init(&my_mutex);  //初始化互斥体

  获取互斥体:

        void inline __sched mutex_lock(struct mutex *lock);

        int __sched mutex_lock_interruptible(struct mutex *lock);

   mutex_lock()和mutex_lock_interruptible()的区别和down()和down_ interruptible ()的区别完全一样,前者引起的睡眠不能被信号打断,而后者可以。

  释放互斥体:

        void __sched mutex_unlock(struct mutex *lock);

  互斥体的使用方法:

        struct mutex my_mutex;  //定义mutex

        mutex_init(&my_mutex);  //初始化mutex

        mutex_lock(&my_mutex);  //获取mutex

         ................       //临界资源

        mutex_unlock(&my_mutex);//释放mutex

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值