4 设定任务优先级(1)(harib13d)
任务B0~B2以同样的速度运行,从公平竞争的角度来说确实不错,不过在某些情况下,我们需要提升或者降低某个应用程序的优先级,因此接下来我们要来实现这样的功能。
在此之前,任务切换间隔都固定为了0.02秒,我们把它修改一下,使得可以为每个任务在0.01秒~0.1秒的范围内设定不同的任务切换间隔,这样一来,我们就能实现最大10倍的优先级差异。
本次的bootpack.h节选
struct TASK {
int sel, flags; /* sel代表GDT编号 */
int priority; /*这里!*/
struct TSS32 tss;
};
变量名“priority”是“优先级”一词的英文写法。
■■■■■
为了应用上面的新结构,我们需要改写mtask.c。
本次的mtask.c节选
struct TASK *task_init(struct MEMMAN *memman)
{
(中略)
task = task_alloc();
task->flags = 2; /*活动中标志*/
task->priority = 2; /* 0.02秒 */
taskctl->running = 1;
taskctl->now = 0;
taskctl->tasks[0] = task;
load_tr(task->sel);
task_timer = timer_alloc();
timer_settime(task_timer, task->priority);
return task;
}
对task_init的改写很简单,没有什么需要特别说明的地方。在这里,我们给最开始的任务设定了0.02秒这个标准值。
■■■■■
接下来是用来运行任务的task_run,我们让它可以通过参数来设定优先级。
本次的mtask.c节选
void task_run(struct TASK *task, int priority)
{
if (priority > 0) {
task->priority = priority;
}
if (task->flags != 2) {
task->flags = 2; /*活动中标志*/
taskctl->tasks[taskctl->running] = task;
taskctl->running++;
}
return;
}
上面的代码中,一开始我们先判断了priority的值,当为0时则表示不改变当前已经设定的优先级。这样的设计主要是为了在唤醒休眠任务的时候使用。
此外,即使该任务正在运行,我们也能使用task_run仅改变任务的优先级。
■■■■■
接着是task_switch,我们要让它在设置定时器的时候,应用priority的值。
本次的mtask.c节选
void task_switch(void)
{
struct TASK *task;
taskctl->now++;
if (taskctl->now == taskctl->running) {
taskctl->now = 0;
}
task = taskctl->tasks[taskctl->now];
timer_settime(task_timer, task->priority);
if (taskctl->running >= 2) {
farjmp(0, task->sel);
}
return;
}
当只有一个任务的时候,如果执行farjmp(0, task—>sel);的话,虽然不会真的切换但确实是发出了任务切换的指令。这时CPU会认为“操作系统怎么会做这种毫无意义的事情呢?这一定是操作系统的bug!”因而拒绝执行该指令,程序运行就会乱套。所以我们需要在farjmp之前,判断任务数量是否在2个以上。
这样一来,对mtask.c的改写就OK了。
■■■■■
现在我们来改写fifo.c。从休眠状态唤醒任务的时候需要调用task_run,我们这次主要就是改写这个地方。说白了,其实我们只是将任务唤醒,并不改变其优先级,因此只要将优先级设置为0就可以了。
本次的fifo.c节选
int fifo32_put(struct FIFO32 *fifo, int data)
/*向FIFO写入数据并累积起来*/
{
(中略)
fifo->free--;
if (fifo->task != 0) {
if (fifo->task->flags != 2) { /*如果任务处于休眠状态*/
task_run(fifo->task, 0); /*将任务唤醒*/
}
}
return 0;
}
■■■■■
最后我们来改写一下HariMain,做一做改变优先级的实验。
本次的bootpack.c节选
void HariMain(void)
{
(中略)
/* sht_win_b */
for (i = 0; i < 3; i++) {
(中略)
task_run(task_b[i], i + 1);
}
(中略)
}
好了,大功告成。
■■■■■
我们为任务B0设置为优先级1,任务B1为2,任务B2为3,因此B2应该是最快的,而B0应该是最慢的,其速度的差异应该正好是3倍的关系。马上“make run”一下。
结果是这个样子
而真机环境下的结果如下。
- 1711130 3234785 4663010
- (1806134) (4758230)
加括号的数值代表偶尔会出现的结果,根据每秒轮到该任务执行的次数不同,数值也会有些差异。如果以任务B0为基准来看,任务B1为1.9倍,任务B2为2.7倍。虽然不是完美的整数倍这一点令人有些不爽,不过用C语言写的程序,多多少少会有些误差。总之,这样的结果已经达到我们的目的了。