嵌入式中锁机制杂谈

        在之前的文章中有提到操作系统中锁机制一般依赖于硬件CPU提供的原子数据操作指令,如SWP, TEST AND SET等原子原语实现。基于此,才能真正保证锁机制的有效实现。

        通过上面原子操作,我们比较容易实现所谓的自旋操作(原子性的原地循环判断条件,直到条件满足才能继续执行后面指令。这里没有直接使用自旋锁表述,为了区分具体的锁机制命名,如自旋锁,互斥锁,信号量,及读写锁)。通过这种自旋操作(被称为基于条件的操作),可以定义延伸出不少锁的概念,或者至少在实现锁时多少都会使用自旋操作语义来实现。如,互斥锁和信号量都是基于任务(线程或者进程)级别使用的,在条件不满足时sleep等待,直到被wakeup,但是判断条件是否满足时也要保证原子自旋操作。

       一般操作系统中普遍的分为任务上下文和中断上下文。嵌入式系统现在一般也可划分为UP(单CPU)和MP(多CPU,此处特指SMP,多CPU存在共享资源。下同)系统。每个CPU上面执行的任务都会存在任务上下文和中断上下文的概念,由操作系统统一进行资源调度和分配。下面针对UP和MP各自存在的任务上下文和中断上下文在实现自旋操作方面进行分析。

       不管UP和MP,只要程序运行路径存在多条时,都会产生竞态(race condition)。竞态可能直接导致了对相同数据的不一致访问,需要对竞态进行约束,从而产生了基于原子操作的锁机制,对某一临界区资源进行保护。

       任何事物处于发展变化当中,都有其两面性,就像阴和阳。使用锁会带来系统性能下降的同时但也保证了逻辑运行的正确性。不能正确分析使用锁的情形,有可能会发生死锁,导致系统崩溃。

       基于自旋操作的自旋锁及其延伸锁机制比较有代表性,我们来看下几种情形下使用自旋锁和中断交互的情况:

       自旋锁:spin_lock()和spin_unlock()

       中断使能和关闭:enable_irq()和disable_irq()

       中断状态保存和恢复:irq_flag_save()和irq_flag_restore()


       在UP和任务上下文中,访问相同资源不涉及中断上下文,每个任务各自运行,任务间共享资源,这种情形不会发生死锁现象,直接使用自旋锁即可(自旋的任务需要等待本任务时间片退出后,再调度其他拥有锁的任务执行释放锁后)。

       任务中:spin_lock();临界区 spin_unlock();

       在UP中,任务和中断上下文时,各任务和中断中访问相同资源时,由于中断响应抢占执行,加锁不当会发生死锁现象。死锁产生为:任务中临界区加锁后,在中断运行中锁无法获得不能退出发生死锁。如何解决:可以在任务加锁时禁止中断,释放锁时使能中断来完成。在中断中使用锁时,应该禁止中断抢占(关中断),但是何时开启中断呢?拿ARM讲,进入中断模式时,自动关闭中断,退出中断模式时自动开启中断,也就是在中断模式使用锁时,不能提前使能中断,否则由于提早使能了中断会导致中断嵌套(如果不支持中断嵌套,程序就会出错)。

      但是发生的锁嵌套需要我们记录下进入锁之前的中断状态flag,锁退出时还原之前的中断状态flag,而不是简单的使能中断enable_irq()所能做到的,如下:

     任务中:flag = irq_flag_save(); disable_irq();spin_lock();临界区..  spin_unlock(); irq_flag_restore(flag );

     中断中:  flag = irq_flag_save(); disable_irq();spin_lock();临界区..  spin_unlock(); irq_flag_restore(flag );


     在MP中和任务上下文中,访问相同资源不涉及中断上下文,每个任务各自运行,任务间及多CPU共享资源,这种情形不会发生死锁现象,直接使用自旋锁即可。自旋锁也是最初基于解决SMP同步机制时提出的。如下:

     任务中:spin_lock();临界区 spin_unlock();

     在MP中,任务和中断上下文时,由于对资源的使用涉及本CPU,其他CPU,一个CPU内的中断上下文和任务上下文等。因此CPU间使用自旋锁保护,本CPU内不同上下文采用自旋锁和开关中断方式来保护。如下:

     多CPU任务中:flag = irq_flag_save(); disable_irq();spin_lock();临界区..  spin_unlock(); irq_flag_restore(flag );

     多CPU中断中:  flag = irq_flag_save(); disable_irq();spin_lock();临界区..  spin_unlock(); irq_flag_restore(flag );

      

  


       



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值