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

[自制简单操作系统] 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个level27     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 register14 //每次给TR赋值的时候,必须把GDT的编号乘以815 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.task2 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

 

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