Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15309824
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类:

2007-10-07 18:58:55

由swi等任务切换想到的一些东东

文章来源:http://gliethttp.cublog.cn[转载请声明出处]

[:以下为FreeRTOS_v4.5.0在at91sam7s64处理器上的task任务创建函数(gliethtp)]
--------------------------------------------------------------------------------------
portEND_SWITCHING_ISR
vPortYieldProcessor
vPortPreemptiveTick

以上3个函数会调用vTaskSwitchContext(),将全局量pxCurrentTCB指向高优先级的task对应的TCB,
1.portEND_SWITCHING_ISR
----在ISR中发生了Semaphore、Q或者Mutex互斥量等事件,事件又使得比进入ISR之前的占用cpu的
    当前运行线程的优先级高,所以需要调用portEND_SWITCHING_ISR,让更高优先级的task线程执行,
    达到RTOS的实时性.
(具体实例可见:demo/arm7_at91sam7s64_iar/serial/Serial.c->__arm void vSerialISR( void )以及
              demo/arm7_at91sam7s64_iar/usb/USBSample.c->__arm void vUSB_ISR( void )
)
2.vPortYieldProcessor
----主动调用taskYIELD()产生软中断,之后软中断异常直接调用vPortYieldProcessor处理程序,
    进而调用vTaskSwitchContext()计算已经就绪的更高优先级task对应的TCB传给全局量pxCurrentTCB,
    之后在portRESTORE_CONTEXT(),顺利恢复到计算出来的就绪的最高优先级task中去执行代码.
3.vPortPreemptiveTick
----在FreeRTOS系统滴答tick时钟里,每1个系统滴答tick都会调用vTaskSwitchContext(),计算下一个
    需要占用cpu的新task,这也直接导致,同优先级的task们,顺利进行轮转调度,所以tick是他们能够
    顺利进行轮转的直接源动力;

由此想到的[gliethtp]:
  假设tick间隔为10ms,那么在用户task中不做任何处理的前提下,
每10ms都会轮转到下1个同优先级的task执行,每个task占用cpu的时间为1个系统tick滴答10ms,
如果用户task在其中夹杂了各种事件处理,延时等待,主动调用taskYIELD()以及某些IRQ中触发事件
等因素之后,就会出现多个同优先级的tasks占用cpu的时间总和为10ms的情况,也就是taskA可能刚刚
因为同优先级的taskB主动调用了taskYIELD()获得了cpu,此时还没有经过2us,系统滴答tick到来,
仅仅执行2us的taskA会在系统滴答tick到达后,又被剥夺cpu,通过计算,taskB可能又获得了cpu,
最糕的情况是每个系统滴答tick都是这样,就像物理学上讲的"共振"一样,那么这种情况下FreeRTOS对
taskA在分配策略上是不公平的,taskA将一直处于饥饿状态,虽然不至于饿死,
如果FreeRTOS修正为基于时间片的轮转调度策略,这种问题可以得到解决,不过实际应用中这样的巧合
可能不会出现,但是这也直接导致我们设计的实际系统如果是关乎人类生命的,那么不要使用轮转
调度,因为这里边存在刚才上面提到的那样一种特殊情况,如果某个计算需要在taskA中完成,而taskA
又迟迟不能完成,当缓存空间耗尽的时候,同步机制开始起作用,其他和计算结果相关的tasks们
因为迟迟等不到结果的到来,而不得不放慢自己的速度甚至悬挂起自己,让出cpu,让taskA能够有更多的机会
获得cpu的使用时间,整个系统的性能开始短时间下降,又因为动态特性,taskA的那种窘困情况并不会一直
持续,所以我们在外边看到我们的应用系统就会出现:一会慢、一会快,走走停停,慢慢悠悠,好像我们欠它200似的.
所以在FreeRTOS实际同优先级task建立之前要考虑清楚,否则可能因为轮转调度MLQ的原因,
出现一些不太希望的现象,当然FreeRTOS以他优秀的架构方式,让我们使用者可以建立优先级完全不同的多个task,
来避开轮转过程中出现的task占用cpu时间不稳定的现象,但是每增加1个优先级,静态空间pxReadyTasksLists就会
多出1个xList结构来维护,扫描时间while(listLIST_IS_EMPTY(&(pxReadyTasksLists[uxTopReadyPriority])))
也就多出了1个循环对应的几条汇编语句,进而也就让cpu关闭IRQ中断的时间又多出了一些,
当然可以权衡,使用FIQ将一些很紧要的中断进行处理,但是因为FIQ可以抢占正在处理IRQ的context上、下文
的代码,所以也就导致FIQ中不能出现portSAVE_CONTEXT()等和FreeRTOS任务切换相关的代码,
所以FIQ中也不能使用事件如Q事件,Semaphore事件等来触发任务,因为FIQ不能再访问全局量或者局部量,
这些量值可能在IRQ或swi中,已经被保存到了旧task中,抑或刚刚恢复了一半.
  另一个就是FreeRTOS关闭中断的时间,可能比较长,从任务切换角度来看主要是由vTaskSwitchContext()计算导致的,
void vTaskSwitchContext( void )
{
    if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
    {
        xMissedYield = pdTRUE;
        return;
    }

    while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
    {
        --uxTopReadyPriority;//直接导致IRQ关闭时间可能很长[gliethttp]
    }
    listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
    vWriteTraceToBuffer();
}
   从事件角度来看,FreeRTOS_v4.5.0使用Queue机制,间接实现了Queue队列事件机制,Semaphore信号机制和Mutex互斥机制
3种机制,而且进入xQueueGenericSend()之后,第一件事情是锁住调度器:vTaskSuspendAll(),将除当前task之外的
所有task不能及时获得cpu使用权,将RTOS机制打了一个不小的折扣,延迟到xTaskResumeAll()才能执行任务切换,不过还好
虽说关断时间有时可能比较长,但是我们还能够忍受,
当然这样做的1个优势是,vTaskSuspendAll()期间,cpu的IRQ中断是可以安全进行的;进入xTaskResumeAll()函数就会关闭
IRQ系统,直到内部函数执行完毕才会重新使能IRQ系统,或者在其中干脆taskYIELD();切换到另1个task,由另1个task完成IRQ
开启工作(或者是当即spsr没有关中断,进而直接打开,或者是切换过去的task继续运行,显示调用开中断函数)这种方式
与ucos-ii的任务切换和中断管理机制一致,这种机制能够计算到IRQ系统关闭时间的最大值;可是xTaskResumeAll()有1个
地方可能使IRQ系统关断时间延长很多,也是由while循环引起的,
while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
{
    //2007-09-29 gliethttp
    //如果调度器被锁,那么事件队列和标准队列上的指针不会调整,
    //所有链表摘除工作都要在这里进行
    vListRemove( &( pxTCB->xEventListItem ) );
    vListRemove( &( pxTCB->xGenericListItem ) );
    prvAddTaskToReadyQueue( pxTCB );

    if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
    {
        xYieldRequired = pdTRUE;
    }
}
因为PendingReadyList队列可能因为IRQ事件风暴,将n多个task同时都打到上面去,这样计算while循环体
也就要有n次,不过还好,他有一个上限值,就是所有可能挂接到PendingReadyList队列上的tasks的总和,执行while(n)
循环体所花费的时间.
  总的来说,每种RTOS都有它优秀的一面和不太理想的一面,根据我们实际的工程应用场合,来自由选择相应的RTOS,
每一种RTOS都不是万能的,某个RTOS优秀的那一面能和我们的实际工程应用的主要因素大部分匹配,并且不太理想的那一面也
不影响到我们什么,那么这个RTOS就可以和我们的工程应用相匹配,
能match上一个实用的RTOS不容易,FreeRTOS还是相当不错的[gliethttp]!

阅读(4114) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-06-11 14:06:19

任务切换时查找优先级可能要关很长时间中断 还有你说的每个时间片轮换不是什么好东西 我认为,可以修改一下内核,定制同优先级n个时间片轮换一次。 但这样有一个结果,就是关中断时间更长了 ralfak@163.com