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>来学习,请看本系列开篇 第六章 继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章 ...
随机推荐
- Network_01
(从实践中学习TCP/IP协议读书笔记) 准备工作: 安装Kali Linux系统: 在VMWare中安装,选Debian 8.x 64bit,ISO镜像地址,在下载完镜像后,在VMWare中把镜像挂 ...
- 主板上来了一个新邻居,CPU慌了!
大家好,我是CPU一号车间的那个阿Q,好久不见,我想死你们了- 不认识我的请去这里这里补补课:完了!CPU一味求快出事儿了! 主板上的新邻居 "阿Q,快别忙了,马上去一趟会议室,领导有重要事 ...
- 用思维导图软件MindManager整理假期
今天带大家使用MindManager2020软件构建出2020年的节假日思维导图. 既然是做2020年的节假日思维导图,那么有个MindManager技巧就是,关于这一类思维导图我们都可以选择时间线导 ...
- 工作中使用mongodb
写了一个mongodb的基类 1 <?php 2 3 namespace BI\Service\MongoDB; 4 5 use MongoDB\Driver\BulkWrite; 6 use ...
- leetcode 108 和leetcode 109
//感想:有时候啊,对于一道题目,如果知道那个点在哪,就会非常简单,比如说这两题,将有序的数组转换为二叉搜索树, 有几个点: 1.二叉搜索树:对于某个节点,它的左节点小于它,它的右节点大于它,这是二叉 ...
- Prometheus Operator自定义监控项
Prometheus Operator默认的监控指标并不能完全满足实际的监控需求,这时候就需要我们自己根据业务添加自定义监控.添加一个自定义监控的步骤如下: 1.创建一个ServiceMonitor对 ...
- 使用Verilog搭建一个单周期CPU
使用Verilog搭建一个单周期CPU 搭建篇 总体结构 其实跟使用logisim搭建CPU基本一致,甚至更简单,因为完全可以照着logisim的电路图来写,各个模块和模块间的连接在logisim中非 ...
- day4(JWT介绍)
1.JWT介绍 1.1jwt原理 最简单理解:jwt本质就是, 把用户信息通过加密后生成的一个字符串 JWT的原则是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户 { "Use ...
- 第4.7节 Python特色的序列解包、链式赋值、链式比较
一.序列解包 序列解包(或可迭代对象解包):解包就是从序列中取出其中的元素的过程,将一个序列(或任何可迭代对象)解包,并将得到的值存储到一系列变量中. 一般情况下要解包的序列包含的元素个数必须与你在等 ...
- 第15.46节、PyQt显示部件:OpenGL Widget部件功能简介及使用案例
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.概述 OpenGL Widget部件是一个Op ...