uC/OS-II的OSSchedLock()和OSSchedUnlock()函数允许应用程序锁定当前任务不被其它任务抢占。
使用时应当注意的是:当你调用了OSSchedLock()之后,而在调用OSSchedUnlock()之前,
千万不要再调用诸如OSFlagPend()、OSMboxPend()、OSMutexPend()、OSQPend()、OSSemPend()之类的事件等待函数!
而且应当确保OSSchedLock()和OSSchedUnlock()函数成对出现,特别是在有些分支条件语句中,要考虑各种分支情况,不要有遗漏!
 
需要一并提醒用户的是:当您调用开关中断函数OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()时也要确保成对出现,否则系统将可能崩溃!
不过,在OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()函数之间调用OSFlagPend()、OSMboxPend()、OSMutexPend()、OSQPend()、OSSemPend()之类的事件等待函数是允许的。

OSSchedLock()

调用OSSchedLock()以后,用户的应用程序不得使用任何能将现行任务挂起的系统调用。

也就是说,用户程序不得调用OSMboxPend()、OSQPend()、OSSemPend()、

OSTaskSuspend(OS_PR1O_SELF)、OSTimeDly()或OSTimeDlyHMSM(),直到OSLockNesting回零为止。

因为调度器上了锁,用户就锁住了系统,任何其它任务都不能运行

下面贴出这个函数的代码 :
#if OS_SCHED_LOCK_EN > 0   //这是个全局变量,在Os_cfg.h中定义
void  OSSchedLock (void)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif    
    
    
    if (OSRunning == TRUE) {                     /* 确认是否是多个任务在运行              */
        OS_ENTER_CRITICAL();
        if (OSLockNesting < 255) {               /* OSLockNesting最大值为255     */
            OSLockNesting++;                     /* Increment lock nesting level                       */
        }
        OS_EXIT_CRITICAL();
    }
}
#endif 
从上锁函数我们可以看出,这个函数就是一个确定任务上锁级数的函数,也就是为OSLockNesting这个变量更新取值的函数。
如果我们在任务里面执行一次该函数,则上锁级数就是1。我们也可以知道,上锁函数的深度最大值为255,我们可以通过上锁到255,到逐级解锁来实现不同的应用。
但这个过程,本人从来没有实现过。
并且补充一点,在上锁函数执行后,若任务遇到中断,则中断函数的执行会为OSIntNesting变量加1,所以上锁函数执行后,CPU一直处于当前任务与中断服务函数之间的运行,

直到解锁函数将OSLockNesting和OSIntNesting的值减到0时。方可解除系统锁定。。。。

转:ucos中的三种临界区管理机制(OS_CRITICAL_METHOD的解释)

熟悉ucos,或者读过Jean.J.Labrosse写过的ucos书籍的人,一定会知道ucos中著名的临界去管理宏:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。

同样是通过关中断来保护临界区,OS_ENTER_CRITICAL/OS_EXIT_CRITICAL一共实现了三种实现方式,如下所示:

  1. #if OS_CRITICAL_METHOD == 1
  2. #define OS_ENTER_CRITICAL() __asm__("cli")
  3. #define OS_EXIT_CRITICAL() __asm__("sti")
  4. #endif
  5. #if OS_CRITICAL_METHOD == 2
  6. #define OS_ENTER_CRITICAL() __asm__("pushf \n\t cli")
  7. #define OS_EXIT_CRITICAL() __asm__("popf")
  8. #endif
  9. #if OS_CRITICAL_METHOD == 3
  10. #define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR())
  11. #define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr))
  12. #endif

第一种方式,OS_ENTER_CRITICAL()简单地关中断,OS_EXIT_CRITICAL()简单地开中断。这种方式虽然简单高效,但无法满足嵌套的情况。如果有两层临界区保护,在退出内层临界区时就会开中断,使外层的临界区也失去保护。虽然ucos的内核写的足够好,没有明显嵌套临界区的情况,但谁也无法保证一定没有,无法保证今后没有,无法保证在附加的驱动或什么位置没有,所以基本上第一种方法是没有人用的。

第二种方式,OS_ENTER_CRITICAL()会在关中断前保存之前的标志寄存器内容到堆栈中,OS_EXIT_CRITICAL()从堆栈中恢复之前保存的状态。这样就允许了临界区嵌套的情况。但现在看来,这种方法还存在很大的问题,甚至会出现致命的漏洞。

在OS_CRITICAL_METHOD=2的情况下,假设有如下代码:

  1. function_a()
  2. {
  3. int a=(1<<31);
  4. OS_ENTER_CRITICAL();
  5. function_b(a);
  6. OS_EXIT_CRITICAL();
  7. }

会出现什么情况?在我的实验中,OS_EXIT_CRITICAL()之后,会出现处理器异常。为什么会出现处理起异常,让我来模拟一下它的汇编代码。之所以是模拟,并非是我虚构数据,而是因为我实际碰到问题的函数复杂一些,理解起来就需要更多的代码。而这个问题是有普遍意义的,所以请允许我来浅显地揭示这个隐藏的bug。

  1. function_a:
  2. push ebp
  3. mov ebp, esp
  4. sub esp, 8
  5. mov 4(esp), 0x80000000
  6. pushfd
  7. cli
  8. mov edi, 4(esp)
  9. mov (esp), edi
  10. call function_b
  11. popfd
  12. mov esp, ebp
  13. ret

这是参照了gcc编译结果的汇编模拟,无论是否加优化选项这一问题都存在。这个问题的起因很简单,gcc想聪明一点,一次把堆栈降个够,然后它就可以在栈上随意放参数去调用其他函数。尤其是在调用函数较多的时候,这种做法就更有意义。而且,gcc这种聪明与优化选项O好像没有太大关系,好像没有什么能禁止它这么做。但问题是,gcc不知道我们的OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()是操作了堆栈的,我尝试过使用__asm__ __volatile__("pushfd \n\tcli":::"memory")来通知gcc内存数据改变了,但显然gcc不认为堆栈也改变了。于是,OS_ENTER_CRITICAL()保存在栈上的状态就被冲掉了,比如被这里调用参数a的值。在恢复时,是否会引发异常,会引发什么异常,这个就要靠运气了。但我相信一个人的运气不会总是那么好的,所以最后别使用OS_CRITICAL_METHOD=2。

第三种,在关中断前,使用局部变量保存中断状态。这也是几乎所有实时操作系统共有的选择。但ucos是一朵奇葩,为了兼容前两种方式,OS_ENTER_CRITICAL()/ OS_EXIT_CRITICAL()宏定义并没有提供传递状态参数的功能。所以它的临界去必须这么用:

  1. function_a()
  2. {
  3. #if OS_CRITICAL_METHOD == 3
  4. int cpu_sr;
  5. #endif
  6. int a = 1<<31;
  7. OS_ENTER_CRITICAL();
  8. function_b(a);
  9. OS_EXIT_CRITICAL();
  10. }

这种代码怎么看怎么别扭,可能是因为在函数体内加了宏定义吧。然后,第三种方法对同一个函数体内的嵌套临界区无法支持,这在一些很长大的函数中使用时或许会造成一定困扰。

好吧,如果有了问题,就要有解决方案,毕竟我不是为了让大家对ucos失去信心的。我们可以参考下一般的实时操作系统是如何实现关中断临界区的,就是以显式的方式用局部变量保存中断状态。

  1. int int_lock()
  2. {
  3. int cpu_sr;
  4. __asm__ __volatile__("pushfd \n\t pop %0\n\t cli":"=r"(cpu_sr));
  5. return cpu_sr;
  6. }
  7. void int_unlock(int cpu_sr)
  8. {
  9. __asm__ __volatile__("push %0\n\t popfd"::"r"(cpu_sr));
  10. }
  11. function_a()
  12. {
  13. int a, cpu_sr;
  14. a=1<<31;
  15. cpu_sr = int_lock();
  16. function_b(a);
  17. int_unlock(cpu_sr);
  18. }

int_lock()和int_unlock()的可以用汇编更高效地实现,也可以选择只恢复中断标志的状态。这种方法让我们显示地管理状态保存的情况,我觉得至少要比宏定义清楚多了

OSSchedLock()函数透析的更多相关文章

  1. ucos_ii 上锁函数OSSchedLock()函数透析

    因为任务调度时一般都是通过OSTIMEDLY()来实现.在这个函数中会对当前的任务执行挂起.同时查看任务调度表中是否有优先级合适的就绪任务.如果当前任务运行时调用OSSchedLock()给调度器上锁 ...

  2. lambda匿名函数透析

    lambda匿名函数透析 目录 1       匿名函数的作用... 1 2       匿名函数的格式... 1 3       匿名函数实例代码... 3   1         匿名函数的作用 ...

  3. OpenCV4Android释疑: 透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰)

    OpenCV4Android释疑: 透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰) 前文曾详细探讨了关于OpenCV的使用,原本以为天下已太平.但不断有人反 ...

  4. Ruby设计模式透析之 —— 适配器(Adapter)

    转载请注明出处:http://blog.csdn.net/sinyu890807/article/details/9400153 此为Java设计模式透析的拷贝版,专门为Ruby爱好者提供的,不熟悉R ...

  5. Ruby设计模式透析之 —— 组合(Composite)

    转载请注明出处:http://blog.csdn.net/sinyu890807/article/details/9153761 此为Java设计模式透析的拷贝版,专门为Ruby爱好者提供的,不熟悉R ...

  6. 透析ARP原理

    对于ARP协议, 我本来是不了解的,只是解决了两个ARP相关的P2的Bug后,也就懂了.本文将从原理的角度对ARP做一个透析. 1. 什么是ARP? ARP(Address Resolution Pr ...

  7. java--序列化及其算法透析

    有关Java对象的序列化和反序列化也算是Java基础的一部分,下面对Java序列化的机制和原理进行一些介绍. Java序列化算法透析 Serialization(序列化)是一种将对象以一连串的字节描述 ...

  8. Excel数据分析 --数据透析表

    数据透析表主要用于各种数据总汇,对各项数据指标进行分类统计 实例分析 如下所示:是一份销售流水数据,有时间,地区,销售员,商品名称,数量,单价和金额几个字段,如下所示: 现在针对不同的数据汇总需求,可 ...

  9. SOFA 数据透析

    数据透传: 在 RPC调用中,数据的传递,是通过接口方法参数来传递的,需要接口方定义好一些参数允许传递才可以,在一些场景下,我们希望,能够更通用的传递一些参数,比如一些标识性的信息.业务方可能希望,在 ...

随机推荐

  1. ListBoxControl 删除选择的项的方法

    public void RemoveSelectItems<T>(BaseListBoxControl listControl)        {            var list ...

  2. tableview: 实现tableview 的 section header 跟随tableview滑动

    方法一:(只有一个headerView)一段 如果你的tableview恰好只有一个headerView,实现这种效果就好办了.把要设置的headerView设置成tableView的header而不 ...

  3. asp.net 动态添加多附件上传.

    最近有人问起动态多文件上传,想要做到类似于邮箱添加附件的效果,这个功能其实比较简单,就是往form中添加file元素.在用户选择完文件后,再添加一个file控件,由于file控件过多,视觉上不好看,所 ...

  4. 独立博客怎样申请谷歌Adsense

    谷歌Adsense广告是眼下个人站长的主要赚钱途径之中的一个,首先是它相对诱人的单位价格,尽管谷歌中文广告相比英文广告单位价格有所折扣,但我的经验是仅仅要你的网页内容和广告keyword有较高的匹配性 ...

  5. iOS开发--通过MultipeerConnectivity完成蓝牙通讯

    iOS开发–通过MultipeerConnectivity完成蓝牙通讯 iOS蓝牙通讯的三种方式: GameKit.framework:iOS7之前的蓝牙通讯框架,从iOS7开始过期,但是目前已经被淘 ...

  6. Java基础知识强化之集合框架笔记14:List集合存储字符串并遍历

    1. List集合存储学生对象并遍历: 需求:存储字符串并遍历 分析: (1)创建集合对象 (2)创建字符串对象 (3)添加字符串对象到集合中 (4)遍历集合 2. 代码示例: package cn. ...

  7. python - 操作RabbitMQ

    python - 操作RabbitMQ     介绍 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议.MQ全称为Mess ...

  8. mvc Action上面加 [HttpPost]

    mvc  Action上面加 [HttpPost]  意思就是这个action只能响应post请求. 如果发get请求这里是没有响应的

  9. 动态拼接 sql的时候 里面 如果有变量的话 按上面的方式进行处理

    set @Sql_Sql = N' select top 1 @m_zw=zw,@m_zh=temp from ket where zd=''ddd'' ' print @Sql_Sql EXEC s ...

  10. html px em pt长度单位(像素 相对长度 点)知识(转)

    html px em pt单位区 一.PX\EM\PT单位介绍 px单位名称为像素,相对长度单位,像素(px)是相对于显示器屏幕分辨率而言的国内推荐:em单位名称为相对长度单位.相对于当前对象内文本的 ...