[自制简单操作系统] 8、多任务(三)——多窗口与优先级

 

前言

>_<" 上一节已经实现了简单的多任务,而且还写了任务挂起函数,用来加快处理~这一节在上面的基础上增加多个窗口,然后又在优先级上面设计了一种分级的优先级模式~

 

一、效果展示

>_<" 如图产生了4个窗口,除了task_a窗口另外窗口是显示1s中的数数。

>_<" 这里的优先级模式是:有优先级较高的层里面有任务时,优先级低的层内的所有任务将会被屏蔽,只有该优先级高的层里面的任务才能进行任务切换~,像本例程是 把任务A是LEVEL1,优先级2;其他3个B任务分别是LEVEL2,优先级分别为1,2,3.这里的优先级是中断时间,优先级1即该任务的中断时间为 0.01s

 

 

二、代码说明

>_<" 在bootpack.h里有保存任务状态段信息的结构体TSS32,然后有任务结构体TASK,接下来是LEVEL的结构体,最后一个结构体是负责管理所有的任务~

 1 /* mtask.c 任务切换相关*/
 2 #define MAX_TASKS                    1000   /* 最大任务数量 */
 3 #define TASK_GDT0                    3             /* 定义从GDT的几号开始分配给TSS */
 4 #define MAX_TASKS_LV    100        //每个level最多100个任务
 5 #define MAX_TASKLEVELS    10             //最多10个level
 6 
 7 struct TSS32 {//task status segment 任务状态段
 8     int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;//保存的不是寄存器的数据,而是与任务设置相关的信息,在执行任务切换的时候这些成员不会被写入(backlink除外,某些情况下会被写入)
 9     int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;//32位寄存器
10     int es, cs, ss, ds, fs, gs;//16位寄存器
11     int ldtr, iomap;//有关任务设置部分
12 };
13 struct TASK {
14     int sel, flags; /* sel用来存放GDT的编号 */
15     int level, priority;
16     struct TSS32 tss;
17 };
18 struct TASKLEVEL {
19     int running; /* 正在运行的任务量数 */
20     int now; /* 这个变量用来记录当前正在运行的任务是哪一个 */
21     struct TASK *tasks[MAX_TASKS_LV];
22 };
23 struct TASKCTL {
24     int now_lv; /* 正在运行的level */
25     char lv_change; /* 在下次任务切换时是否需要改变LEVEL */
26     struct TASKLEVEL level[MAX_TASKLEVELS];//最多10个level
27     struct TASK tasks0[MAX_TASKS];
28 };
29 extern struct TIMER *task_timer;
30 struct TASK *task_init(struct MEMMAN *memman);//初始化任务控制
31 struct TASK *task_alloc(void);//分配一个任务
32 void task_run(struct TASK *task, int level, int priority);//设置一个任务的LEVEL和优先级
33 void task_switch(void);//如果LEVEL改变了要改变当前的LEVEL然后从当前的LEVEL中找到当前任务进行切换
34 void task_sleep(struct TASK *task);//删除任务的时候要考虑LEVEL的变化~

>_<" 在初始化里面主要多了把所有LEVEL的running(即:正在运行的任务数)置0,now(即:当前正在执行的任务的标号)置0,然后分配一个任务设置level和优先级,并加入level。其中第10行是用来设置任务切换时决定接下来切换到哪个LEVEL。接下来,分配一个时间并给它设置~

 1 for (i = 0; i < MAX_TASKLEVELS; i++) {//把每一层的level全都设置为0
 2         taskctl->level[i].running = 0;
 3         taskctl->level[i].now = 0;
 4 }
 5 task = task_alloc();
 6 task->flags = 2; /* 活动中标志 */
 7 task->priority = 2; //任务优先级//0.02s定时器
 8 task->level = 0;    /* 第0层 */
 9 task_add(task);        //加入level中
10 task_switchsub();    /* 用来任务切换时决定接下来切换到哪个LEVEL */
11 load_tr(task->sel);
12 //向TR寄存器写入这个值,因为刚才把当前运行任务的GDT定义为3号,TR寄存器是让CPU记住当前正在运行哪一个任务
13 //每当进行任务切换时,TR寄存器的值也会自动变换,task register
14 //每次给TR赋值的时候,必须把GDT的编号乘以8
15 task_timer = timer_alloc();
16 timer_settime(task_timer, task->priority);

>_<" 在没有改变之前,task_run中下一个要切换的任务是固定不变的,不过现在就不同了,如果本次task_run启动一个比当前活动中的任务LEVEL更高的任务,那么下次任务切换时,就得无条件的切换到更高优先级的LEVEL中。此外,如果当前任务中的LEVEL被下调,那么就得把其他LEVEL的有先任务放在前面。综上所述:我们需要再下次切换时先检查LEVEL,因此将lv_change置为1。

 1 void task_run(struct TASK *task, int level, int priority)
 2 {
 3     if (level < 0) {
 4         level = task->level; /* 不改变level */
 5     }
 6     if (priority > 0) {
 7         task->priority = priority;
 8     }
 9 
10     if (task->flags == 2 && task->level != level) { /* 改变活动中的LEVEL */
11         task_remove(task); /* 这里执行之后flag的值会变为1,于是下面的语句也会被执行 */
12     }
13     if (task->flags != 2) {
14         /* 从休眠状态唤醒 */
15         task->level = level;
16         task_add(task);
17     }
18 
19     taskctl->lv_change = 1; /* 下次切换任务时检查LEVEL */
20     return;
21 }

>_<" 所以在任务切换里,如果上面的LEVEL变化了,就要把第10~11行进行当前level的设置,下面就是很正常的切换了~

 1 void task_switch(void)
 2 {
 3     struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv];//当前任务的LEVEL
 4     struct TASK *new_task, *now_task = tl->tasks[tl->now];
 5     tl->now++;
 6     if (tl->now == tl->running) {
 7         tl->now = 0;
 8     }
 9     if (taskctl->lv_change != 0) {//LEVEL之间变换了
10         task_switchsub();//用来在任务时决定接下来切换到哪个LEVEL,直接从头开始找,找到第一个LEVEL中有任务的返回
11         tl = &taskctl->level[taskctl->now_lv];
12     }
13     new_task = tl->tasks[tl->now];
14     timer_settime(task_timer, new_task->priority);
15     if (new_task != now_task) {
16         farjmp(0, new_task->sel);
17     }
18     return;
19 }

>_<" 下面的任务挂起也比较简单了~

 1 void task_sleep(struct TASK *task)
 2 {
 3     struct TASK *now_task;
 4     if (task->flags == 2) {
 5         /* 如果处于活动状态 */
 6         now_task = task_now();
 7         task_remove(task); /* 执行此语句的话,flags将被置为1 remove其实就是从数组中删除一个*/
 8         if (task == now_task) {
 9             /* 如果让自己休眠需要进行任务切换 */
10             task_switchsub();
11             now_task = task_now(); /* 在设定后获取当前任务的值 */
12             farjmp(0, now_task->sel);
13         }
14     }
15     return;
16 }

>_<" 在main函数里分别对4个窗口的任务做如下设置

1 task_a = task_init(memman);//初始化任务a//初始化任务管理器,task_init会返回自己的构造地址,我们将这个地址存入fifo.task
2 fifo.task = task_a;//可以自动管理,待唤醒的task(//记录休眠任务名)
3 task_run(task_a, 1, 2);//将任务A的LEVEL设置为1,优先级2,B的3个任务LEVEL是2,所以优先级低

1 task_run(task_b[i], 2, i + 1);;//启动任务,LEVEL2,优先级1,2,3 

 

三、相关链接

没有加入优先级,只是用平均分配的模式的多窗口链接13c:http://pan.baidu.com/s/1nt4w6RB

加入LEVEL模式的优先级时的多窗口链接13e:http://pan.baidu.com/s/1eQw3sQY

 

posted @ 2014-09-26 23:46  beautifulzzzz  阅读(2057)  评论(1编辑  收藏  举报