ucosiii学习(3)——任务调度和时间片轮转

1.任务级调度器 OSSched()

系统初始化后会自动创建几个任务,可以看到所调用的创建任务函数OSTaskCreate的最后都会调用OSSched()函数(任务级调度器)。

Description: This function is called by other uC/OS-III services to determine whether a new, high priority task has been made ready to run.  This function is invoked by TASK level code and is not used to reschedule tasks from ISRs (see OSIntExit() for ISR rescheduling).

该函数定义在os_core.c中,可以看到 该函数体中依次执行

CPU_INT_DIS();

OSPrioHighRdy   = OS_PrioGetHighest(); 

CPU_INT_DIS();        //  cpu_sr = CPU_SR_Save(); 关闭中断
OSPrioHighRdy   = OS_PrioGetHighest();    //获取就绪任务的最高优先级
if (OS_CFG_TASK_IDLE_EN == DEF_ENABLED)
    OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; //获取优先级最高的就绪任务
if (OSTCBHighRdyPtr == OSTCBCurPtr)    //优先级最高的就绪任务为当前任务
   {                       
        CPU_INT_EN();                 //CPU_SR_Restore(cpu_sr); 打开中断                     
        return;
    }

 OS_TASK_SW();           //判断没有中断和被锁住后,调用该汇编代码                                 
 CPU_INT_EN();

2.中断级调度器 OSIntExit()

Description: This function is used to notify uC/OS-III that you have completed servicing an ISR.  When the last nested ISR has completed, uC/OS-III will call the scheduler to determine whether a new, high-priority task, is ready to run.

在中断级调度器中真正完成任务切换的就是中断级任务切换函数OSIntCtxSW(),与任务级切换函数OSCtxSW()不同的是,由于进入中断的时候现场已经保存过了,所以OSIntCtxSW()不需要像OSCtxSW()一样先保存当前任务现场,只需要做OSCtxSW()的后半部分工作,也就是从将要执行的任务堆栈中恢复CPU寄存器的值。

其中:OSIntNestingCtr为中断嵌套计数器,进入中断服务函数后我们要调用OSIntEnter()函数,在这个函数中会将OSIntNestingCtr加1,用来记录中断嵌套的次数。而OSIntExit()是在退出中断服务函数时调用的,因此中断嵌套计数器要减1。如果减1之后,OSIntNestingCtr还大于0,说明还有其他的中断发生,那么就跳回到中断服务程序中,不需要做任务切换。

任务调度点:
1、释放信号量或者发送消息,也可通过配置相应的参数不发生任务调度。 
2、使用延时函数OSTimeDly()或者OSTimeDlyHMSM()。 
3、任务等待的事情还没发生(等待信号量,消息队列等)。 
4、任务取消等待。 
5、创建任务。 
6、删除任务。 
7、删除一个内核对象。 
8、任务改变自身的优先级或者其他任务的优先级。 
9、任务通过调用OSTaskSuspend()将自身挂起。 
10、任务解挂某个挂起的任务。 
11、退出所有的嵌套中断。 
12、通过OSSchedUnlock()给调度器解锁。 
13、任务调用OSSchedRoundRobinYield()放弃其执行时间片。 
14、用户调用OSSched()。
有时候我们并不希望发生任务调度,因为始终有一些代码的执行过程是不能被打断的。此时我们就可以使用函数OSSchedLock()对调度器加锁,当我们想要恢复任务调度的时候就可以使用函数OSSchedUnlock()给已经上锁的任务调度器解锁

3.时间片轮转调度器OS_SchedRoundRobin()

UCOSIII允许一个优先级下有多个任务,每个任务可以执行指定的时间(时间片),然后轮到下一个任务,这个过程就是时间片轮转调度,当一个任务不想在运行的时候就可以放弃其时间片。 
如果某一优先级下有多个任务话,这些任务是如何被调度和运行的:先判断该任务的时间片是否有剩余,如果有就直接返回不切换;如果没有,就进行切换。每次任务切换后运行的都是处于就绪任务列表OSRdyList[ ]链表头的任务,当这个任务的时间片用完后这个任务就会被放到链表尾,然后再运行新的链表头的任务。

猜你喜欢

转载自blog.csdn.net/weixin_42480952/article/details/83016748