[自制简单操作系统] 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

时间: 2024-11-10 01:20:25

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

[自制简单操作系统] 6、多任务(一)

#前言# >_<" 这里主要是多任务的初探~比较简单,主要是尝试保存当前任务.任务切换.恢复当前任务,而真正的多任务要比这个复杂的多,因为包含互不干扰,甚至是高度优化的并行技术! 一.保存当前任务: >_<" 当向CPU发出切换命令的时候,CPU会先把寄存器中的值全部写入内存中,这样当切换回来时,可以从中断的地方继续执行.接下来,为了运行下一个程序,CPU会把所有的寄存器中的值从内存中读取出来,这就完成了一次切换. >_<" 这里的结构TS

[自制简单操作系统] 3、内存管理和窗口叠加

1.本次主要进展 >_<" 这次主要学习了系统内存管理和窗口叠加~由于上两篇都做了详细的框架说明和介绍,这里直接上代码! 2.文件及函数构成 >_<" 这里和第二篇相比,把鼠标和键盘的相关函数独立出来放进各自相应的文件中,并主要在内存管理和窗口叠加进行探索,同时还有部分代码整理~ 1 /* In this file, not only have the defination of the function, but also 2 hava the descrip

[自制简单操作系统] 7、多任务(二)——任务管理自动化&amp;任务休眠

前言 >_<" 这里仿照窗口管理的方式将任务管理也修改成相应的管理模式,这样可以灵活的添加多个任务,而不必每次都要修改任务切换函数:此外还在任务休眠做了尝试,通过将任务挂起和唤醒从而加快运行速度~ 一.任务管理自动化 >_<" 为了仿照窗口管理模式对任务进行管理,于是在bootpack.h里做如下定义: 1 /* mtask.c 任务切换相关*/ 2 #define MAX_TASKS 1000 /* 最大任务数量 */ 3 #define TASK_GDT0

[自制简单操作系统] 5、杂七杂八(高分辨率和键盘输入)

前言: >_<" 这几天正在研究一个好玩的,准备写<软硬结合第三篇——科班的还是可以修电脑的>,可是当前遇到个技术难点——WHDI,所以操作系统这里就慢了好大一节啦!但是以操作系统多任务的思路,感觉还是把这个优先级并不是太低的进程拿出来做一下吧!毕竟技术难点有时候需要灵感的哈~(不过有大神知道VGA接口的通信原理吗?求给个好一点的链接看看!).回到正题上来,这次学的东西有点杂,主要就是高分辨率和键盘输入相关~对于前者和汇编及硬件联系较多(具体可以查VBE Video El

[自制简单操作系统] 2、鼠标及键盘中断处理事件[PIC\GDT\IDT\FIFO]

1.大致介绍: >_<" 大致执行顺序是:ipl10.nas->asmhead.nas->bootpack.c PS: 这里bootpack.c要调用graphic.c.dsctbl.c.fifo.c.int.c实现功能,其中有些函数还必须汇编来写,所以单独写一个汇编文件naskfunc.nas,为了方便看全部函数和结构体,所以写一个bootpack.h来写一些结构体和函数声明~ >_<" 下面是编译图解:最终生成的haribote.img可放在软盘

[自制简单操作系统] 1、从0-1到汇编再到c语言的奥秘

目录: 1.用0-1编写最简单的操作系统 2.用汇编改写上面0-1程序 2.1 只用DB的汇编改写版  2.2 加入RESB汇编的改写版  2.3 进一步使用汇编替换0-1文件  2.4 核心程序也用汇编改写  2.5 向汇编程序中加入IPL(启动程序装载器)  2.6 从启动区执行操作系统(读盘的应用) 3.汇编和C语言混合开发 3.1 32位开发及C语言混合开发引入 3.2 汇编引入C语言(用汇编写C语言函数)  3.3 C语言实现内存写入  3.4 C语言指针的强大  3.5 色号设定与调

[自制简单操作系统] 4、计时器(线性表实现优化中断)

1.第一版:数组方式[09d] >_<" 在bootpack.h里面的timer.c的声明和结构体: 1 /* timer.c */ 2 #define MAX_TIMER 500 //最多500个定时器 3 struct TIMER{ 4 unsigned int flags;//flags记录各个寄存器状态 5 unsigned int timeout;//用来记录离超时还有多长时间,一旦这个剩余时间为0,程序就往FIFO缓冲区里发送数据,定时器就是用这种方法通知HariMain

《30天自制操作系统》笔记(08)——叠加窗口刷新

<30天自制操作系统>笔记(08)--叠加窗口刷新 进度回顾 上一篇中介绍了内存管理的思路和算法,我们已经可以动态申请和释放内存了.这不就是堆(Heap)么.在此基础上,本篇要做一段程序,一并解决窗口和鼠标的叠加处理问题. 问题 在之前的<<30天自制操作系统>笔记(05)--启用鼠标键盘>篇,已经能够移动鼠标了.但是遗留了如下图所示的一个小问题. 我们希望的情形是这样的: 实际上,当前版本的OS还没有窗口图层的东西.本篇要做一段程序,一并解决窗口和鼠标的叠加处理问题.

《30天自制操作系统》笔记(09)——绘制窗口

<30天自制操作系统>笔记(09)--绘制窗口 进度回顾 上一篇中介绍了图层式窗口管理的思路和算法.在此基础上,本篇就解决绘制窗口及其简单的优化问题. 这里稍微吐槽一下<30天自制操作系统>原作者.全书我刚刚看了三分之一,写得确实不错,但是我能感受到原作者是习惯用汇编语言和汇编思维来写程序的.虽然书里尽量使用了C语言,但给我一种用C写汇编的感觉.也可能是原作者故意简化了OS开发过程,方便初学者理解吧.幸好这在我预料之中,一开始我就打算先看完这本书然后自己再从零设计OS的. 看似立体