4 设定任务优先级(1)(harib13d)

任务B0~B2以同样的速度运行,从公平竞争的角度来说确实不错,不过在某些情况下,我们需要提升或者降低某个应用程序的优先级,因此接下来我们要来实现这样的功能。

在此之前,任务切换间隔都固定为了0.02秒,我们把它修改一下,使得可以为每个任务在0.01秒~0.1秒的范围内设定不同的任务切换间隔,这样一来,我们就能实现最大10倍的优先级差异。

本次的bootpack.h节选

  1. struct TASK {
  2. int sel, flags; /* sel代表GDT编号 */
  3. int priority; /*这里!*/
  4. struct TSS32 tss;
  5. };

变量名“priority”是“优先级”一词的英文写法。

■■■■■

为了应用上面的新结构,我们需要改写mtask.c。

本次的mtask.c节选

  1. struct TASK *task_init(struct MEMMAN *memman)
  2. {
  3. (中略)
  4. task = task_alloc();
  5. task->flags = 2; /*活动中标志*/
  6. task->priority = 2; /* 0.02秒 */
  7. taskctl->running = 1;
  8. taskctl->now = 0;
  9. taskctl->tasks[0] = task;
  10. load_tr(task->sel);
  11. task_timer = timer_alloc();
  12. timer_settime(task_timer, task->priority);
  13. return task;
  14. }

对task_init的改写很简单,没有什么需要特别说明的地方。在这里,我们给最开始的任务设定了0.02秒这个标准值。

■■■■■

接下来是用来运行任务的task_run,我们让它可以通过参数来设定优先级。

本次的mtask.c节选

  1. void task_run(struct TASK *task, int priority)
  2. {
  3. if (priority > 0) {
  4. task->priority = priority;
  5. }
  6. if (task->flags != 2) {
  7. task->flags = 2; /*活动中标志*/
  8. taskctl->tasks[taskctl->running] = task;
  9. taskctl->running++;
  10. }
  11. return;
  12. }

上面的代码中,一开始我们先判断了priority的值,当为0时则表示不改变当前已经设定的优先级。这样的设计主要是为了在唤醒休眠任务的时候使用。

此外,即使该任务正在运行,我们也能使用task_run仅改变任务的优先级。

■■■■■

接着是task_switch,我们要让它在设置定时器的时候,应用priority的值。

本次的mtask.c节选

  1. void task_switch(void)
  2. {
  3. struct TASK *task;
  4. taskctl->now++;
  5. if (taskctl->now == taskctl->running) {
  6. taskctl->now = 0;
  7. }
  8. task = taskctl->tasks[taskctl->now];
  9. timer_settime(task_timer, task->priority);
  10. if (taskctl->running >= 2) {
  11. farjmp(0, task->sel);
  12. }
  13. return;
  14. }

当只有一个任务的时候,如果执行farjmp(0, task—>sel);的话,虽然不会真的切换但确实是发出了任务切换的指令。这时CPU会认为“操作系统怎么会做这种毫无意义的事情呢?这一定是操作系统的bug!”因而拒绝执行该指令,程序运行就会乱套。所以我们需要在farjmp之前,判断任务数量是否在2个以上。

这样一来,对mtask.c的改写就OK了。

■■■■■

现在我们来改写fifo.c。从休眠状态唤醒任务的时候需要调用task_run,我们这次主要就是改写这个地方。说白了,其实我们只是将任务唤醒,并不改变其优先级,因此只要将优先级设置为0就可以了。

本次的fifo.c节选

  1. int fifo32_put(struct FIFO32 *fifo, int data)
  2. /*向FIFO写入数据并累积起来*/
  3. {
  4. (中略)
  5. fifo->free--;
  6. if (fifo->task != 0) {
  7. if (fifo->task->flags != 2) { /*如果任务处于休眠状态*/
  8. task_run(fifo->task, 0); /*将任务唤醒*/
  9. }
  10. }
  11. return 0;
  12. }

■■■■■

最后我们来改写一下HariMain,做一做改变优先级的实验。

本次的bootpack.c节选

  1. void HariMain(void)
  2. {
  3. (中略)
  4. /* sht_win_b */
  5. for (i = 0; i < 3; i++) {
  6. (中略)
  7. task_run(task_b[i], i + 1);
  8. }
  9. (中略)
  10. }

好了,大功告成。

■■■■■

我们为任务B0设置为优先级1,任务B1为2,任务B2为3,因此B2应该是最快的,而B0应该是最慢的,其速度的差异应该正好是3倍的关系。马上“make run”一下。

4 设定任务优先级(1)(harib13d) - 图1

结果是这个样子

而真机环境下的结果如下。

  1. 1711130 3234785 4663010
  2. (1806134) (4758230)

加括号的数值代表偶尔会出现的结果,根据每秒轮到该任务执行的次数不同,数值也会有些差异。如果以任务B0为基准来看,任务B1为1.9倍,任务B2为2.7倍。虽然不是完美的整数倍这一点令人有些不爽,不过用C语言写的程序,多多少少会有些误差。总之,这样的结果已经达到我们的目的了。