OS第六章
OS第七次实验
多进程
添加一个进程体
添加进程B,首先设置i的初值为0x1000,这样来方便程序运行时的时候能区分。其余地方与A一致。
相关变量和宏
Minix中定义了一个数组,叫做tasktab的数组,用于存放一个进程的开始地址,堆栈等。初始化时,只需要for循环读取然后填充到对应的进程表项即可。
- 声明数组类型,s_task,分别为进程体,堆栈大小,已经名字。
- 在global.h中,增加进程数组,task_table。并记得是在头文件中加入引入的结构体。
- 在proc.h中定义进程的堆栈大小以及新的进程B的声明。
- 进行初始化,主要初始化LDT,将人物入口地址,堆栈栈顶赋给对应的进程表。
- 为每个进程都在GDT中分配了一个描述符来用对应进程的LDT。
初始化进程表
for循环读取相关数据
LDT
改成循环就可,就是用初始化段描述符的函数,然后中间用的是段名转物理,线性转物理。
问题,为什么要移位?
修改中断处理程序
原有代码只有进程的保存和恢复而没有进程的切换。我们需要对其进行增加进程切换相关的部分。只需要使esp指向不同的进程表即可。那就是在离开内核栈,为esp赋值之前对p_proc_ready进行赋值即可
创建一个时钟中断的.c函数,作用是打印一个字符。并且p_proc_ready++,到进程表尾则回到第一个。
添加一个任务的步骤总结
- 添加一个进程体
- tasktable添加项
- 在proc.h添加进程栈的大小
- proto.添加函数声明
系统调用
运转过程
- 控制权交给引导扇区
- 加载Loader
- 跳到Loader
- 加载kernel
- 跳到kernel
- 切换到kernel的GDT
- 初始化8259A
- 初始化IDT
- 初始化GDT中的TSS和LDT的两个描述符,以及初始化TSS
- 初始化进程表
- 指定时钟中断处理程序
- 让8259A可以接受时钟中断
- restart
- 进程开始运转
实现简单的系统调用
一个简单的系统调用
- 用get_ticks来统计中断发生的次数。
- 首先在syscall中定义这个调用函数。
- 将eax赋值为_NR_get_ticks.这样OS就可以在中断发生时调用的是这个函数
- 中断号设为了90.只要不和前面的冲突就行。
- 定义INT_VECTOR_SYS_CALL对应的中断门。
- 修改save,将eax改成esi
- 在kernel中写syscall:
- 调用save函数用来保存相关寄存器
- 调用sys_call_table [eax],即指向对应的get_ticks函数
- 然后将eax放到esi+eaxreg-p_stackbase即将上面的函数的返回值放入到进程表中
- 在proc.c中添加函数sys_get_ticks
- 在proto.h添加函数声明
- 在进程中调用相关函数
为了实现真正的时钟中断计数功能:
- 首先在global.h中定义全局变量ticks
- 在main.c中初始化
- 时钟中断处理程序中添加一个ticks++
- 让get_ticks函数返回当前ticks的值。
- 让进程打印ticks
get_ticks的应用
- 可以用来判断时间,来取代delay
- 改变时间中断的间隔
- 计数器输入频率为1193180HZ,计数器为16位的,所以最大值为65535,所以时钟中断发生频率位1193180/65535约为18.2HZ
- 为了改变时钟中断发生频率,需要修改计数器的值,即修改8253
- 首先通过端口43H来修改太复杂,这里查看其数据格式,6 7位为计数器选择位,这里要修改counter0,值应该为00,由于计数器为16位,所以高低位都要写,所以读写为即5 6 为都要为11 ,模式位为2, 所以123应该为 010 ,第0位是0,综上是00110100即0x34
- 在main,c初始化8253
- 宏定义中,HZ设为100(即发生频率为100),rate_geneator的值为0x34
- 现在中断发生时间即为10ms了
- 新的延迟函数,接受一个参数,为毫秒数,读取当前的时钟中断发生次数,然后进行一个while循环,当循环到当前中断数减去开始中断数乘以10的数字比接受参数大时,推出循环。所以会有一个的误差(即延迟函数发生时,可能马上要开始下一个时钟中断了,又因为不止一个进程在执行,所以可能发生中断重入,导致已经满足条件时切换到了其他进程,并且打印也会浪费时间)
进程调度
- 使不同的进程的延迟时间不同,这里调用上面的milli_delay函数,使进程A,B,C延迟300,900和1500ms.

- 查看输出情况
A有182个,B有63个,C有35个和BA延迟时间比3以及AC延迟时间比5基本吻合
为了实现调度算法
实现思路为:每个进程都有个新的变量,这个变量的值有大有小,进程每获得一个运行周期,就减一,直到减到0,这个进程就不再执行了,直到所有的进程都为0了,这时候再都给赋值为原来的量
现在proc.h给进程表结构体添加新成员,一个是用来递减的ticks,一个是用来恒定表示值的priority。一开始的ticks等于priority,当所有ticks都变为0时,再给他们赋值为priority.

在main.c里对其进行赋值。其中ABC的时间片分别为150 50 30

写调度算法函数:在proc.c中实现函数schedule.c函数的意义为,遍历所有进程,剩余最多时间的进程将会优先执行,当所有进程剩余时间都为0时,都重新赋值为priority。

修改时钟中断函数,将原来的直接执行下一个进程改为调用调度算法函数,并且在ticks++下面加入当前进程的ticks--

为了确保是调度算法发生的作用,这里将ABC的延迟时间都改为200
结果图

可以看到其比例大体为2.57:1.31:1,与15:5:3差别较大,为了解决这个问题
- 修改进程,让其打印当前ticks
- 修改调度算法,使其打印进程时间片
- 注释掉重新赋值的语句,以便观察
- 增加清空屏幕的函数,便于观察
- 输出结果如图

总结
- 整个执行分为三个阶段,第一个阶段,由于A的比BC的都多,所以只有A在调度,直到和B的时间一样多,即执行了100个ticks
- 第二个阶段,A和B同时被调度,直到和C一样的时候才下一阶段,因为每此只会减去一个ticks,所以执行了20*2个
- 第三阶段,ABC都被调度,这时候执行了30*3个ticks
- 所以执行时间之比应该为230:130:90即2.56:1.44.1,与上述结果大致相同
这样做,执行时间还需要计算,并不直接对应其优先级,为了方便,我们在clock_handler里加入一个判断,即只有当ticks变成0时,才转移控制权。

结果如图

第二个实验
思路,给进程表增加新的变量,当前队列,当前队列的运行时间(即时间片大小),和进程状态(0是就绪,1是运行,2是等待,3是终止)。添加进程,使得有5个进程A 、B 、C 、D、E,然后修改调度算法和时钟中断函数,使得其能够实现多级反馈队列调度算法以及进程状态的切换。具体实现如下
首先在proc.h中修该进程表,添加成员state(表示其状态),queue(表示进程所在的队列),time_remain(表示当前队列的运行时间)
这里先添加进程(
初始化时,state均为0,初始所在队列均为第一个队列,其运行时间即当前队列的时间片,由于A、B、C、D、E的运行时间分别为3,8,4,5,7,所以这里分别设其priority为15,40,20,25,35。这里的第一轮时间片是定义的一个常量,另外还有第二第三个,因为要求三个队列的时间片分别为1,2,4,所以其大小分别为5,10和20。
开始修改调度算法。
。更改时钟中断,完成时间片轮换和队列切换等
最后的实验结果截图,是符合预期的

OS第六章的更多相关文章
- 【windows核心编程】 第六章 线程基础
Windows核心编程 第六章 线程基础 欢迎转载 转载请注明出处:http://www.cnblogs.com/cuish/p/3145214.html 1. 线程的组成 ① 一个是线程的内核 ...
- 第六章:Reminders实验:第二部分[Learn Android Studio 汉化教程]
Learn Android Studio 汉化教程 Reminders Lab: Part 2 This chapter covers capturing user input through the ...
- Spring实战第六章学习笔记————渲染Web视图
Spring实战第六章学习笔记----渲染Web视图 理解视图解析 在之前所编写的控制器方法都没有直接产生浏览器所需的HTML.这些方法只是将一些数据传入到模型中然后再将模型传递给一个用来渲染的视图. ...
- RHCE学习笔记 管理1 (第六章 第七章)
第六章 利用linux 文件系统权限文件访问 1.linux文件系统权限 文件的权限分为: rwx 读/写/执行 ls -l /home 查看/home下文件 ls -ld /home ...
- Flask 教程 第十六章:全文搜索
本文翻译自The Flask Mega-Tutorial Part XVI: Full-Text Search 这是Flask Mega-Tutorial系列的第十六部分,我将在其中为Microblo ...
- oranges 笔记第六章
OS 第六次实验随笔 第六章6.1-6.3相关的问题 进程状态保存与恢复 哪些状态 何时保存 保存在哪 如何恢复 特权级变换 用户进程到内核 内核回到用户进程 再次理解TSS .堆栈 从外环进入内环( ...
- 【C++】《C++ Primer 》第十六章
第十六章 模板与泛型编程 面向对象编程和泛型编程都能处理在编写程序时不知道类型的情况. OOP能处理类型在程序允许之前都未知的情况. 泛型编程在编译时就可以获知类型. 一.定义模板 模板:模板是泛型编 ...
- 精通Web Analytics 2.0 (8) 第六章:使用定性数据解答”为什么“的谜团
精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第六章:使用定性数据解答"为什么"的谜团 当我走进一家超市,我不希望员工会认出我或重新为我布置商店. 然而, ...
- 《Entity Framework 6 Recipes》中文翻译系列 (30) ------ 第六章 继承与建模高级应用之多对多关联
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第六章 继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章 ...
随机推荐
- vue中父子间传值和非父子间传值
vue传值一般分三种方式:父组件向子组件传值.子组件向父子间传值.非父子组件进行传值 一.父组件向子组件传值:父组件引用子组件后,通过数据绑定(v-bind)向子组件传值 父组件: <templ ...
- 解析MindMapper选项中的鱼骨选项
MindMapper思维导图可以画鱼骨图,而且完成的相当漂亮,我们可以在选项设置中定义鱼骨图图的默认样式.下面本文就分析了MindMapper选项中可以更改哪些鱼骨图设置. 我们首先打开MindMap ...
- ELK---- Elasticsearch 使用ik中文分词器增加拓展热词
进入到我们ik分词器安装目录下的config目录 cd /usr/local/myapp/elasticsearch-6.4.3/plugins/ik/configvi IKAnalyzer.cfg. ...
- PHP 获取本周、今日、本月的起始时间戳
当前周的开始时间(周一)$begintime = mktime(0, 0, 0, date('m'), (date('d') - (date('w')>0 ? date('w') : 7) + ...
- CSP.2020
自闭jpg. 就说说 PJ 吧. TG炸的原因主要是因为PJ的炸裂以及T1--所以就直接分析根本原因了. # 参考补题链接 # # 推荐博客链接 # 0x00 考前一天晚上. 在LH巨佬家吃了饭,前往 ...
- 拿到这份 Java、C++ 软件开发完整学习路线图,我面试再也没挂过..
大家好,我是柠檬. 柠檬哥作为一个普通大学.非计算机专业,自学后端技术进入腾讯做后端开发工作,我自己也是非科班自学计算机成功转行软件开发(有想听柠檬哥转行之路经历的吗,可以留言告诉我,人多就写写),体 ...
- 3D网页小实验——将txt配置文本转化为3D陈列室
设计目标:借鉴前辈编程者的经验将简单的配置文本转化为3D场景,并根据配置文件在场景中加入图片和可播放的视频,最终形成可浏览的3D陈列室. 一.使用效果 1.txt配置文件: (博客园的富文本编辑器会改 ...
- SpringBoot打包成Docker镜像
1. 本文环境 Maven:3.6.3(Maven配置参考) SpringBoot version:2.3.4.RELEASE Docker version: 19.03.11(Docker搭建参考) ...
- go语言之---数组(array)和切片(slice)
一.数组 1.什么是数组? 1.数组是一系列同一类型数据的集合 2.数组中包含的每个数据被称为数组元素 3.一个数组中包含的元素个数成为数组长度 4.数组的长度是固定的 5.一个数组可以由零个或者多个 ...
- Linux 硬盘挂载及开机挂载
一.分区 主分区.扩展分区.逻辑分区的区别 主分区:包含操作系统启动所必需的文件和数据的硬盘分区,如需在硬盘上安装操作系统,该硬盘必须得有一个主分区 扩展分区:除主分区外的分区,不能直接使用,必须再划 ...