中国IEEE
关于我们 | 会员登陆 | 收藏本站 | 留 言 薄
 

 | 网站首页 | 电子知识 | 单片机知识 | 电路设计 | 微电子技术 | SCADA系统 | 资源下载 | 给我留言 | 视频教程 | ieee | 
热门搜索关键字: 单片机教程 | 三极管微电子 |  C语言汇编语言SCADA元器件IEEE |
cnieee.com baidu
栏目导航  
栏目更新推荐  
·单片机实现数据远程监控
·LCD驱动芯片1335控制器C51源程
·C51 内存优化…
·KEIL C51支持的完整芯片…
·Small RTOS51中队列的一处隐患…
·MCS-51单片机地址指针及应用
·MCS51辛普生积分程序
·MCS51的排序程序(ASM)
点击TOP(10)  
  • 此栏目下没有热点文章
  • 图片文章  

    单片机实现数据远程…

    单片机控制的模拟开…

    最常应用的流水闪烁…

    第二章   Keil C软…
     
    您现在的位置: 中国IEEE中国电气电子工程师网 >> 单片机知识 >> 行业动态 >> 正文

    Small RTOS51中队列的一处隐患
    文章来源:不详 点击数: 更新时间:2008-6-6 【字体:
    (欢迎光临中国IEEE,希望本文能对您有所帮助http://www.cnieee.com)


    相关文章:

    MCS51的排序程序(ASM)
    MCS51的三字节无符号除法程序(ASM)
    robots.txt和Robots META标签…
    MAX+PLUS II快速入门…

  • 上一个文章:

  • 下一个文章:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
     
    关于〖Small RTOS51中队列的一处隐患〗的最新评论:
      
    引 言
        Small RTOS5l是一款专门为80C5l系列单片机设计的实时操作系统(实际上应该称其为实时内核),大部分代码用C语言编写,易于移植,十分适合于资源紧张的8位机。同时,它也是学习嵌入式操作系统原理极好的入门材料。本人就是在学习完SmallRTOS5l的基础上进一步学习了著名的uC/0S-II,受益颇多。 

    1 问题描述
        在将Smau RTOS51应用于实验室某项目时,发现了一个奇怪的问题。简单说来,就是一个以无条件方式申请消息的任务竟然在没有取到消息的情况下,以指示“等待超时”的代码返回了。
        在这里,首先解释一下任务申请消息的两种方式:无条件方式和超时方式。所谓五条件方式是指任务申请消息时,如果暂时没有消息可取,则任务将一直等待消息,直至取到为止;而超时方式是指任务等待消息是有时间限制的,超过所设定的最大时间,即便没有取到消息,函数也可以正常返回,只是返回值不是消息,而是“超时代码”(此方式可以防止任务因取不到消息而被永久性挂起)。可见,如果任务以无条件方式申请消息,那么函数若能够返回,则说明任务一定是取到消息了,而返回值又怎么可能是“等待超时”呢?经过仔细分析SmallRTS5l的源代码,找到了问题产生的根源。
        假定有任务IDX以超时方式调用OSQPend()函数申请消息。OSQPend()函数首先会把IDX放到此消息队列的等待任务表中,然后再去判断队列中是否有消息。最佳情况是队列中确实有消息,则OSQPend()再把IDX从此消息队列的等待任务表中删除,接着OSQPend()返回,任务取到消息。
        此刻,假定消息队列中设有消息。那么,OSQPend()就会调用OSClearSigna1(OSRunningTaskID())和OS-Sched()这两个系统函数,迫使IDX进入休眠态,同时调度器调度下一个最高优先级的就绪任务来运行。假定任务IDY被选中,且IDY在运行中通过调用OSQIntPost()函数向此消息队列发送了一则消息。则OSIntPost()将把所有等待这个消息队列的任务中优先级最高的那个任
    务唤醒,并且把它从该消息队列的等待任务表中删除,假定它就是IDX。
        当任务IDY进入休眠态后,操作系统才会调度IDX来运行。于是IDX从上次被强迫休眠的地方开始运行,即从OSQPend()函数中紧接着OSSched()的那条指令开始执行。具体来说,OSQPend()将首先查看IDX是否满足超时条件(用来判断任务是因为等待超时被唤醒的还是因为确实取到消息而被唤醒的),若超时时限尚未到达,OSQPend()再接着检查消息队列中是否已经有了消息。根据上面的假定,可以知道任务IDX确实是因为取到消息而被唤醒的。于是,OSQpend()把IDX从此消息队列的等待任务表中删除,OSQPend()正常返回。这样,任务IDX取到消息,接着运行。
        以上都没有什么问题,但是,有一种情况被忽略了,而正是这种情况的出现导致了任务IDX被长时间挂起,就算队列中有消息存在,IDX也无法被唤醒,只能等到其超时为止。
        为讨论方便,不妨仍按上述假定情况来分析。当任务IDX被唤醒且IDY进入休眠状态后,系统必将调度下一个优先级最高的就绪任务来运行。在前面,认为这个任务就是IDX,然而此时,假定它是另一个比IDX优先级更高的任务IDZ(因为有可能是中断把IDZ唤醒的,所以中断退出时,操作系统强制IDY进入休眠态,转而调度IDZ运行)。非常巧合的是,IDZ在运行的过程中向同一个消息队列也申请了消息。由于之前IDY已经向消息队列发送过一条消息,则IDZ将正常取到此条消息。于是,消息队列中的消息数减为O(Buf[0]==0)。在任务IDZ进入休 眠后,任务IDX被操作系统调入CPU运行。同样,函数OSQPend()首先查看IDX是否等待超时。如果没有超时再检查消息队列中是否存在消息。注意到先前已经假定消息被任务IDZ给取走了,所以检查的结果当然是队列中不存在消息。IDX就只好再次进入休眠,函数OSSched()调度别的任务运行。
        于是问题出现了。IDX是因为暂时取不到消息而被挂起的,但此时这个消息队列的等待任务表中已经投有IDX的踪影了,它之前就已被那个发送消息的IDY在OSQIntPost()函数中给删除了。
        结果,即使后面有任务再次向队列中发送消息,IDX也取不到了,因为消息发送函数OSQIntPost()已经无法从消息队列的等待任务表中找到IDX了,它将被长时间挂起,直至超时。也就是说,任务IDX明明可以取到消息的,却取不到,最后只能以指示其等待超时的代码返回。
        这还是一种相对来说不太严重的错误,无非就是任务没取到消息,以超时返回而已.如果任务IDX以无条件方式申请消息,而又恰恰发生了上面的情况,会有什么样的后果呢?由于OSQPend()函数自身的特性,所谓五条件等待就是把超时时间设为0。结果任务IDX被唤醒后,OSQPend()必然会检测到其已超时,然后又会检测到队列中没有消息,所以就必然以“超时代码”返回。结果就发生了文章开头所说的一幕;一个必须在取到消息后才能返回的任务,居然在没有取到消息的情况下以指示其等待超时的代码返回了。

    2 解决方法
        问题已经找到,就有解决的办法.以《嵌入式实时操作系统SmallRT0s5l原理与应用》(陈明计,北京航空航天大学出版社,2004)中程序清单7.5为例。书中的代码如下:
    #if OS_MAX_TASKS<9              //把当前任务加入到此消息队
                                        //列的等待任务表中
        Buf[3]=OSMapTbl[OSRunnmgTasklD()]; (5)
    #else
        if(OSRunningTasklD()<8){ (6)
        Buf[3]=OSMap Tbl[OSRunningTasklD()]; (7)
        else{
        Buf[4] |= OSMapTbl[OSRunningTasklD( ) &()x07]; (8)
        }
    #endif
        while(Buf[O]==0) //消息队列中暂时投有消息 (9)
        {
    #ifdef_C51_
        SP=SP+sizeof(Buf)。 (10)
        *((uint8 0S_Q_MEM_SEL * data*)(SP+l-slzeof(Buf))=Buf; (11)
    #endif{
        OSClearSignal(OSRunningTask()); //当前任务进入休眠
                                     &nb

    [1] [2] 下一页

    | 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明网站地图 | 名站导航 | 管理登录 | 
    本站资源部分来自互联网,如侵犯您的权利,我们将予以删除  鲁ICP备08006092号
    本站欢迎同类网站做友情链接,QQ留言
    中国IEEE 中国电气电子工程师网 版权所有