| 第五步:用时钟中断实现分时(Time-Sharing)多任务 |
和上一步的例子相比,这一步的例子把任务切换功能挂在时钟中断处理程序上。这样,每一个时钟中断到达的时候,这个时钟中断处理程序就会调用__TaskSwitch函数,从而实现一次任务切换。由于这个切换方式是自动进行的,所以任务切换对用户程序来说是透明的。
这个时钟中断处理程序的代码片断如下:
void interrupt ClockIsr(void)
{
...
__TaskSwitch();
}
1.问:分时(Time-Sharing)多任务的基本原理是什么?
答:分时多任务的基本原理是使用时钟中断周期性地进行线程切换。由于这种切换是对线程透明的(即在线程不知道的情况下进行的),从而在效果上说,使每个线程都获得一个虚拟的处理器。
2.问:在线程切换函数___TaskSwitch中,在调用线程切换调度函数___TaskSchedule之前的堆栈指针为什么要设置为ScheduleStack+1024,而不是ScheduleStack? 答:这是因为在i86上,和一般数据区相比堆栈在内存中的结构是反序的,即栈底在高端地址,栈顶在低端地址。同时,在入栈的时候堆栈指针的地址是递减的,在出栈的时候堆栈指针的地址是递增。所以,当需要把SP指针指向堆栈的栈底时,实际上是把SP指针指向这个堆栈的最高端地址ScheduleStack+1024。
3.问:在这个实例程序中总共有多少个堆栈?为什么?
答:如果创建了N个线程,那么总共需要N+1个堆栈。多出的这一个堆栈是由线程切换调度函数使用的。
4.问:在进行线程切换的时候为什么要关中断?
答:在进行线程切换的时候,需要保存当前线程的处理器状态,同时恢复另外一个线程的处理器状态。如果在执行这个操作的时候被中断并发生其它的线程切换(注意:在分时多任务下中断可能会导致线程切换),当前线程的处理器状态就不能完整地被保存,从而导致当前线程的运行状态被其它线程破坏。
5.问:实现线程切换的基本原理是什么?
答:实现线程切换的基本原理是:通过保存当前线程的处理器状态(主要是指所有寄存器的值 - 包括PC或IP寄存器)并恢复下一个线程的处理器状态,从而使处理器在不同线程之间实现处理器状态的完全转移。通过使用这种保存/恢复的方法,确保了一个线程在运行时不会破坏其它线程的处理器状态,从而使多个线程能够共享一个处理器。
6.问:在这个实例程序运行结束后,整个系统为什么出现"死机"?
答:这其实不是死机。这是因为这个实例程序在运行结束后把处理器控制权转移到了一个根线程(根线程是这个实例程序开始运行时指定的第一个线程,其它子线程是由根线程创建的),而这个根线程在此时进入了一个空闲循环,从而使整个系统看起来似乎是停机了。
7.问:通常用unsigned定义一个变量的时候需要明确定义变量的类型,格式为:unsigned type variable 为什么有些地方可以直接这样定义:unsigned variable? 答:在C语言中,用unsigned定义一个变量的时候有一个默认的数据类型为int,如果没有明确指定数据类型那么数据类型为默认值,即unsigned variable = unsigned int variable
【编写者:易昭华】