因为我利用一个排序的链表来保存就绪列表,所以调度程序容易实现。它只是检测正在运行的任务与最高优先级的就绪任务是否是一个任务和同样的优先级。如果是,调度任务完成。否则,它会启动一个从前者到后者的设备场景的切换。这里是用C++实现的代码。
/**************************************************************
*
* Method : schedule()
*
* Description : Select a new task to be run.
*
* Notes : If this routine is called from within an ISR, the
* schedule will be postponed until the nesting level
* returns to zero.
*
* The caller is responsible for disabling interrupts.
*
* Returns : None defined.
*
**************************************************************/
void
Sched::schedule(void)
{
Task * pOldTask;
Task * pNewTask;
if(state != Started) return;
//
// Postpone rescheduling until all interrupts are completed.
//
if(interruptLevel != 0)
{
bSchedule = 1;
return;
}
//
// If there is a higher-priority ready task, switch to it.
//
if(pRunningTask != readyList.pTop)
{
pOldTask = pRunningTask;
pNewTask = readyList.pTop;
pNewTask->state = Running;
pRunningTask = pNewTask;
if(pOldTask == NULL)
{
contextSwitch(NULL, &pNewTask->context);
}
else
{
pOldTask->state = Ready;
contextSwitch(&pOldTask->context, &pNewTask->context);
}
}
} /* schedule() */
正如你从代码中看到的一样,有两种情况调度程序不启动设备场景的切换。第一种情况是如果多任务没有被启用的时候。这是必要的,因为有时应用程序员想要在调度程序真正启动之前创建其任务的一些或者全部。在那种情况下,应用程序的main 例程会类似于下面这段
tb程序。每次一个Task 对象被创建的时候,调度程序就被调用(注1)。然而,因为调度程序为了检查多任务是否已被启动而检测变量state 的值,所以直到start()被调用以后才会发生设备场景的转换。
#include "adeos.h"
void taskAfunction(void);
void taskBfunction(void);
/*
* Create two tasks, each with its own unique function and priority.
*/
Task taskA(taskAfunction, 150, 256);
Task taskB(taskBfunction, 200, 256);
/**************************************************************
*
* Method : main()
——————————————————————————————————
注 1:记住,任务的创建是我们调度点其中的一个。如果调度程序已经启动了,新任务仍然可能是最高优先级的就绪任务。
* Description : This is what an application program might look like
* if ADEOS were used as the operating system. This
* function is responsible for starting the operating system only.
*
* Notes : Any code placed after the call to os.start() will never
* be executed. This is because main() is not a task,
* so it does not get a chance to run once the scheduler is started.
*
**************************************************************/
void
main(void)
{
os.start();
// This point will never be reached.
} /* main() */
因为这是一段重要的代码,所以让我重新讲解你正在看的东西。这是一个你可能作为ADEOS 用户写出的应用代码的例子。你在开始加入头文件adeos.h 和声明你的任务。在你声明了你的任务和调用os.start 之后,
tbw任务函数taskAfunction 和taskBfunction 开始执行(以伪并行的方式)。当然,taskB 在这两个任务中具有最高的优先级(200),因此它将先运行。然而,只要它由于任何原因放弃对处理器的控制,其他的任务就有机会运行。另一种 ADEOS 调度程序不进行设备场景切换的情况是在中断进行期间。操作系统跟踪目前运行的中断服务例程的嵌套级别,井且只有在嵌套级是零的时候才允许设备场景切换。如果调度程序是从一个ISR 调用的(就像它在时钟节拍期间一样),bSchedule 标志被置位,表明只要最外层的中断处理程序退出,调度程序就应该再次被调用。这个被延迟的调度加快了整个系统中断响应的时间。