上一篇讲了UCOS的移植和多线程程序的编写,如果是刚开始接触实时操作系统,一定对其中的多线程很好奇,到底是怎么实现的呢?
首先要了解两个指针,一个是PC指针存放在R15寄存器,另一个是SP指针存放在R13寄存器。
下面三点对理解程序切换很重要:
1.PC是个指路器,它指向哪儿,处理器就运行哪儿的。哪个程序占有了PC,哪个程序就占有了处理器。所谓的切换就是 PC<-目标地址。系统是通过把待运行程序的地址赋予程序计数器PC来实现程序的切换的。
2.程序切换前需要将原有任务环境保存,运行环境包括了两部分:处理器中的运行环境和内存中的运行环境。处理器里需要保存的就是寄存器组里的数据(如下图),而内存里需要保存的是当前任务执行的堆栈。那当前任务代码呢?放心,保存了PC指针,到时候切换回来PC会指路的。
3.UCOS还会创建一个任务控制块OS_TCB的结构体,控制块里保存了堆栈栈顶指针,任务当前状态,任务优先级别等信息。程序代码、私有堆栈、任务控制块是任务的三要件。任务控制块提供了运行环境的存储位置。恢复一个任务的流程如下图:
搞懂任务切换的原理就可以在深入理解其他的函数了,先来说说执行任务调度的函数OS_Sched()
void OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
OS_ENTER_CRITICAL();
if (OSIntNesting == 0u) { /* Schedule only if all ISRs done and ... */
if (OSLockNesting == 0u) { /* ... scheduler is not locked */
OS_SchedNew();
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */
#if OS_TASK_PROFILE_EN > 0u
OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */
#endif
OSCtxSwCtr++; /* Increment context switch counter */
OS_TASK_SW(); /* Perform a context switch */
}
}
}
OS_EXIT_CRITICAL();
}
通过反查OS_Sched()的使用情况,这里不全部列出,执行这些函数的时候都会进行任务调度,而任务调度的时候会查找最高优先级的程序执行。
在某个任务的while1{…}循环里,必须要用上调度函数,才能在多任务间调度,实现任务切换。
未完待续