简介
一个后台的运行任务可能由于外部中断停止运行,中断使前台任务运行。当前台任务完成后,后台任务从中断处恢复运行。如果调度程序是后台的一部分,那么在当前正在运行的后台任务完成前,调度程序都不能运行。调度程序调度后台任务运行,任务完成后,再把控制权返回给调度程序,这时调度程序检查任务队列,看队列中是否有就绪任务。如果有,首先设置计时器,然后激活运行队列中的第一个任务。如果没有,调度程序则不断循环检测计时器,一直等到有一个就绪任务运行。调度程序也可能调用一个“闲散”任务,这是一个没有其他事情做时才运行的任务。例如闲散任务可以用来检测前述程序中的stop信号,或者用来与操作台交互作用等等。采用这种调度方法时,不得不对上述程序做一些改动。1
task1一id—task—create(&function1,&data 1,tsample 1,run—continuous)
task2一id—task—create(&function2,&data2,tsample2,run—continuous)
task3一id—task—create(&stop—check,&data3,0,deep—background)
enter--task-queue(task1--id)
enter--task--queue(task2--id)
enter--task--queue(task3--id)
上述程序中的deep—background即表示闲散任务。因为调度程序也是后台的一部分,使任务进入作业队列还没有开始运行,只有显式地应用调度程序才会使它运行。这样一旦调度程序开始,程序可能将不再返回主程序段,一直到系统结束。因此如果有一个闲散任务,调度程序必须知道闲散任务的作用和功能。因为一有空闲,闲散任务就要运行,所以采样时间表示为零。
调度程序的数据结构任务描述子的模块结构
指向函数的指针task--function
指向结构的指针 task—data
整型量task--type
整型量task-state
浮点型(或整型) sample--time
浮点型(或整型) time—left
指向结构的指针 next-task
每次创建一个新任务,给任务描述子分配内存;当任务移出之后,释放分配的空间。任务之间由描述子内的链接指针next—task链接。task—type规定任务类型。任务状态task—state用来跟踪任务的行为。当任务创建时,并不激活;任务进入作业队列后,或者处于激活状态,或者处于不激活状态。采样时间由sample—time给出,剩余时间time--left则指出到下个任务开始运行还剩多少时间。
任务链接指针的工作情况。其中A,B,C的采样时间分别为50ms,70ms,40ms,假设系统启动时C任务运行。
当前运行任务完成后,调度程序让它的剩余时间time—Ieft恢复等于它的采样时间。同时检查任务队列,把这个任务放到正确的位置,重新排序队列,调整链接指针。例如C任务完成后不是插在B任务后面而是插在B任务前面,因此打断了A任务到B任务的链接。
另外有一个保存不激活任务的队列,如果允许有一个以上的闲散任务,则还要增加一个闲散任务队列。因为所有任务描述子,即任务结点,由指针链接,只需要改变指针,就能重排队列。
调度程序current—task=head—of—queue
设置计时器current—task—time—left
不断循环
一直重复到时间结束
执行闲散任务
执行current-task→task-function(current-task→task-data)
If(current-task→task-type=run-conlinuous)
current-task→last-time=current-task→sample-time
把当前任务移到队列中的正确位置
Else
把当前任务移到不激活队列
If (任务队列不空)
current-task=head-of-queue
设置计时器current-task→time-left
Else
关断计时器
其中的当前任务由描述子结构表示。
优点后台调度程序的优点是容易编程和与硬件的交互作用少,但后台调度也受到一些限制。这主要是由于一个后台任务一旦开始,直到它完成以前其他后台任务不能运行,为此所有后台任务实际上有相同的优先级。一个任务具有高优先级表示当到达它的运行时间,它能够中断正在运行的任意较低优先级的任务。如果用后台调度,高优先级任务也不能中断低优先级任务。
另一个限制是采样周期长的任务,其执行时间应比最短的采样间隔短。如果不是这样,采样周期短的任务的实际间隔将很不稳定。因为只要CPU有空闲时间,闲散任务就开始运行,所以要防止闲散任务和下一个运行任务的冲突,让任务的运行比调度稍慢一点。如果闲散任务很快,冲突少,这样可以更充分地利用CPU资源。为了解决冲突问题,最简单的办法是在每次循环调度中只运行一次闲散任务。这样对采样周期长的程序很适用,但CPU时间的利用率不高。较复杂的办法是设法检查计时器的剩余时间,如果剩余时间多,就运行闲散任务。这意味着计时程序要返回当前运行周期的剩余时间,或者用户必须向调度程序发送闲散任务该运行多长时间的信息,调度程序通过检查计时获得这些信息。
如果几个任务运行时间相近,优先级相同,后台调度是有用的。如果CPU的全部负载适度,任务将顺利地循环运行。如果任务间的执行时间和或优先级变化范围大,调度程序将很难裁决任务间的冲突。如果任务都要占用大片CPU时间,将会经常出现时间冲突,导致不规律的计时。当然对优先级相同的任务,这不是由于后台调度的过失,任何调度方法都会发生这类问题。如果使用小片CPU时间,当采样周期增长到二倍以上时间片时,仍旧可能有调度冲突。这种冲突是不可避免的,但可以通过适当分解任务把冲突减到最小。