整个UCOSII嵌入式操作系统的任务调度策略便是如此,现在进行一个总结:
①某个任务在执行中,每隔一定周期发生滴答时钟中断,在中断中遍历整个任务链表,更新每个任务的延时时间,修改就绪状态。
②任务执行完毕后,进入延时函数,在延时函数中会把当前任务挂起(清空当前任务的就绪状态,使其进入未就绪状态),然后根据查表发找到在就绪任务中,优先级最高的那一个任务。
③找到新任务以后,人工强制发生一个中断,保存上个任务的堆栈信息,弹出下个任务的堆栈信息,同时更改PC指针,进行任务切换。
经过以上三个步骤,便可以完成任务的调度。
现在回到第一篇提出的那个问题:UCOSII到底是如何保证它的实时性的呢?
如果任务的调度都是发生在当前任务进入延时之后,似乎操作系统根本无法自身的保障实时性。
比如一个优先级最低的任务由于某些处理非常耗费时间,它一直无法进入延时,导致无法进入任务切换,那么优先级高的任务反而是一只都无法被执行了……
同样在第一篇说过,UCOSII系统除了在当前任务进入延时函数会发生调度之外,还有别的时机会进行任务切换:
1.当前任务进入了延时。
2.当前任务被挂起。
3.当前任务执行时,发生了某些中断。
第1点我们已经全部讲完,第2点非常好理解,我们现在看一个函数:OSTaskSuspend()
这个函数的作用是把某个任务挂起(也就是不进行调度),现在来分析一个实例:
有一个任务调用了这个函数:
void App1_task(void *pdata) { while(1) { if (OS_ERR_NONE != OSTaskSuspend(OS_PRIO_SELF)) { Dbg_SendStr("App1_task Suspend Error£¡\r\n"); } delay_ms(10); }; }
当前任务执行了红色代码之后,便会把自身挂起来,如果没有再别的地方对它进行激活,这个任务便永远也不会执行下去了。
深入分析OSTaskSuspend函数:
INT8U OSTaskSuspend (INT8U prio) { BOOLEAN self; OS_TCB *ptcb; INT8U y; #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif #if OS_ARG_CHK_EN > 0u if (prio == OS_TASK_IDLE_PRIO) { /* Not allowed to suspend idle task */ return (OS_ERR_TASK_SUSPEND_IDLE); } if (prio >= OS_LOWEST_PRIO) { /* Task priority valid ? */ if