操作系统开发系列—13.i.进程调度 ●
上面的三个进程都是延迟相同的时间,让我们修改一下,尝试让它们延迟不同的时间。
void TestA()
{
int i = 0;
while (1) {
disp_str("A.");
milli_delay(300);
}
} void TestB()
{
int i = 0x1000;
while(1){
disp_str("B.");
milli_delay(900);
}
} void TestC()
{
int i = 0x2000;
while(1){
disp_str("C.");
milli_delay(1500);
}
}
运行后,数一数可以知道,输出中共有A字母140个,B字母51个,C字母32个,所以A和B的个数之比是2.745,A和C的个数之比是4.345,这两个数字与3(进程B和A的延迟时间之比)和5(进程C和A的延迟时间之比)是基本吻合的。

为进程表添加新的成员,proc.h:
typedef struct s_proc {
STACK_FRAME regs; /* process registers saved in stack frame */
u16 ldt_sel; /* gdt selector giving ldt base and limit */
DESCRIPTOR ldts[LDT_SIZE]; /* local descriptors for code and data */
int ticks; /* remained ticks */
int priority;
u32 pid; /* process id passed in from MM */
char p_name[16]; /* name of the process */
}PROCESS;
在进程表中添加了两个成员:ticks是递减的,从某个初值到0.为了记住ticks的初值,我们另外定义一个变量priority,它是恒定不变的。当所有的进程ticks都变为0之后,再把各自的ticks赋值为priority,然后继续执行。
ticks和priority最初赋值如下,main.c的kernel_main():
proc_table[0].ticks = proc_table[0].priority = 150;
proc_table[1].ticks = proc_table[1].priority = 50;
proc_table[2].ticks = proc_table[2].priority = 30;
对于进程调度,我们可以单独写一个函数,叫做schedule(),放在proc.c中:
PUBLIC void schedule()
{
PROCESS* p;
int greatest_ticks = 0; while (!greatest_ticks) {
for (p = proc_table; p < proc_table+NR_TASKS; p++) {
if (p->ticks > greatest_ticks) {
greatest_ticks = p->ticks;
p_proc_ready = p;
}
} if (!greatest_ticks) {
for (p = proc_table; p < proc_table+NR_TASKS; p++) {
p->ticks = p->priority;
}
}
}
}
同时修改时钟中断处理函数,clock.c:
PUBLIC void clock_handler(int irq)
{
ticks++;
p_proc_ready->ticks--; if (k_reenter != 0) {
return;
} schedule();
}
同时我们将所有进程的延迟时间全改为相同的值,把所有milli_delay的参数改成200.
make运行的结果发现,虽然各个进程延迟的时间都相同,但由于改变了它们的优先级,运行的时间明显不同,这说明我们的优先级策略生效了!
但是,当前的A、B、C三个字母的个数之比是139:71:54,大体相当于2.57:1.31:1,与进程优先级5:1.67:1(15:5:3)相差比较大。为什么呢,首先修改各个进程,让它们各自打印一个当前的ticks。然后修改一下schedule(),加上几条打印语句等等后再次运行,


修改clock_handler,clock.c:
PUBLIC void clock_handler(int irq)
{
ticks++;
p_proc_ready->ticks--; if (k_reenter != 0) {
return;
} if (p_proc_ready->ticks > 0) {
return;
} schedule(); }
这样,在一个进程的ticks还没有变成0之前,其他进程就不会有机会获得执行。
从运行结果可以明显看出,进程A先执行,然后是B,再然后是C,与原先有了很大的差别。原因在于进程A的ticks从150递减至0之后,才把控制权给B,B用完它的ticks(50)之后再给C,然后各自的ticks被重置,继续下一个类似的过程。可以看到,进程A在150ticks内执行8次循环,B在50ticks内执行3次循环,C在30ticks内执行2次循环。这样就很直观了。
我们再把它们的优先级改小一点:
proc_table[0].ticks = proc_table[0].priority = 15;
proc_table[1].ticks = proc_table[1].priority = 5;
proc_table[2].ticks = proc_table[2].priority = 3;
然后把各个进程的延迟时间改成10ms:
void TestA()
{
int i = 0;
while (1) {
disp_str("A.");
milli_delay(10);
}
}
运行结果如下,可以看出,现在打印出的字符的个数之比非常接近15:5:3:

【源码】
操作系统开发系列—13.i.进程调度 ●的更多相关文章
- 操作系统开发系列—13.g.操作系统的系统调用 ●
在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是 ...
- 操作系统开发系列—13.a.进程 ●
进程的切换及调度等内容是和保护模式的相关技术紧密相连的,这些代码量可能并不多,但却至关重要. 我们需要一个数据结构记录一个进程的状态,在进程要被挂起的时候,进程信息就被写入这个数据结构,等到进程重新启 ...
- 操作系统开发系列—13.h.延时操作
计数器的工作原理是这样的:它有一个输入频率,在PC上是1193180HZ.在每一个时钟周期(CLK cycle),计数器值会减1,当减到0时,就会触发一个输出.由于计数器是16位的,所以最大值是655 ...
- 操作系统开发系列—13.e.三进程
我们再来添加一个任务,首先添加一个进程体: void TestC() { int i = 0x2000; while(1){ disp_str("C"); disp_int(i++ ...
- 操作系统开发系列—13.d.多进程 ●
进程此时不仅是在运行而已,它可以随时被中断,可以在中断处理程序完成之后被恢复.进程此时已经有了两种状态:运行和睡眠.我们已经具备了处理多个进程的能力,只需要让其中一个进程处在运行态,其余进程处在睡眠态 ...
- 操作系统开发系列—13.c.进程之中断重入
现在又出现了另外一个的问题,在中断处理过程中是否应该允许下一个中断发生? 让我们修改一下代码,以便让系统可以在时钟中断的处理过程中接受下一个时钟中断.这听起来不是个很好的主意,但是可以借此来做个试验. ...
- 操作系统开发系列—13.b.进程之丰富中断处理程序
首先打开时钟中断: out_byte(INT_M_CTLMASK, 0xFE); // Master 8259, OCW1. out_byte(INT_S_CTLMASK, 0xFF); // Sla ...
- 微信公众号开发系列-13、基于RDIFramework.NET框架整合微信开发应用效果展示
1.前言 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解. 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发.微信公众平台定制开发,都不知道这些能给 ...
- 操作系统开发系列—1.HelloWorld ●
org 07c00h ;伪指令,告诉编译器程序会被加载到7c00处 mov ax, cs mov ds, ax mov es, ax call DispStr ;调用显示字符串例程 jmp $ ;无限 ...
随机推荐
- G++ 参数介绍(转载)
g++参数介绍 From: http://www.cnblogs.com/lidan/archive/2011/05/25/2239517.html gcc and g++分别是gnu的c & ...
- Android抓包方法(一)之Fiddler代理
Android抓包方法(一) 之Fiddler代理 前言: 做前端测试,基本要求会抓包,会分析请求数据包,查看接口是否调用正确,数据返回是否正确,问题产生是定位根本原因等. 不管是之前做HTML5手机 ...
- 吐槽坑爹的微软win store app审核
从学习win store app 开发到做出第一个应用 博客园cnblogs 花了一个多月的全部业余和上班空闲时间, 上周在端午节放假期间终于完成了计划的全部开发和测试, 6月10号怀着无比激动的心情 ...
- Javascript动画效果(一)
Javascript动画效果(一) 前面我们介绍了Javascript的回到顶部效果,今天呢,我们对Javascript动画做进一步的研究.在这篇博文中我们只介绍简单的匀速运动.简单的缓冲运动和简单的 ...
- JS的跳转
需要在下面的button中实现跳转,之前直接写了个<a>标签,但是在手机上的效果太差了,这是老大写的 js跳转.记下来,要学会贯通. <div class="ps-lt&q ...
- ASP.NET MVC系列:控制器的Edit方法
在前面我们已经介绍了如何创建控制器.视图和数据模型,运行之前的项目并打开Movies主页,将鼠标悬停在“编辑”菜单上,你会看到浏览器右下角显示了“编辑”链接的地址
- 【vbs】vbs写ini文件
这两天在折腾给一个项目打安装包,第一次接触软件打包,用的Advanced Installer(以下简称AI),应该说如果安装过程没有特殊动作(常规动作指释放文件.写注册表.建快捷方式等)的话,倒挺傻瓜 ...
- 使用MiniProfiler跟踪MVC + EF + Bootstrap 2 权限管理系统的性能消耗
安装MiniProfiler 在MVC + EF + Bootstrap 2 权限管理系统入门级(附源码)文章中下载了它的源码,调试模式下打开一个页面都要再2.5秒以上,所以使用MiniProfile ...
- Repository 设计模式介绍
在DDD设计中大家都会使用Repository pattern来获取domain model所需要的数据. 1.什么是Repository? "A Repository mediates b ...
- 使用DocX开源组件,实现动态数据的填充。
1.先解释一下,什么叫做动态数据,动态数据指的是,一条数据的格式固定,但数据的条数不固定. 2.应用环境,在一个表格当中如果,现在表格有三行n列,如果你需要在表格第一行后添加同等规格的一行或n行,应该 ...