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>来学习,请看本系列开篇 第六章 继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章 ...
随机推荐
- SpringBoot使用策略模式+工厂模式
为了防止大量的if...else...或switch case代码的出现,可以使用策略模式+工厂模式进行优化. 在我的项目当中,报表繁多,所以尝试了这种方式进行优化报表的架构.代码很简单,如下: Fa ...
- 关于Java多线程看这一篇就够了,从创建线程到线程池分析的明明白白
前言 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,即进程空间或(虚空间).进程不依赖于线程而独立存在,一个进程中可以启动多个线程. 线程是指进程中的一个执行流程,一个进程中可 ...
- 看阿里P7讲MyBatis:从MyBatis的理解以及配置和实现全帮你搞懂
前言 MyBatis 是一款优秀的持久层框架,一个半 ORM(对象关系映射)框架,它支持定制化 SQL.存储过程以及高级映`射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结 ...
- Spring 事件监听机制及原理分析
简介 在JAVA体系中,有支持实现事件监听机制,在Spring 中也专门提供了一套事件机制的接口,方便我们实现.比如我们可以实现当用户注册后,给他发送一封邮件告诉他注册成功的一些信息,比如用户订阅的主 ...
- leetcode 1046
class Solution { public int lastStoneWeight(int[] stones) { MaxHeap s=new MaxHeap(stone ...
- Mac 安装Homebrew慢的问题解决
一开始安装,在官网上的命令: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/ma ...
- 2020.11.26 IntellJ idea激活码失效解决方法(最新idea激活码及安装参数!)
今天是2020年11月26号,小伙伴们是不是有发现自己的idea激活码失效了,不瞒大家,小编也是一个JAVA开发者,到了公司打开idea,然后就发现事情不妙,经过1个多小时的摸索,终于把最近的安装参数 ...
- MySQL replace into那些隐藏的风险
目录 replace into时存在主键冲突 replace into时存在唯一索引冲突 replace into时存在主键冲突&唯一索引冲突 存在问题 结论 MySQL中 replace i ...
- 简单RTSCamera实现
using System.Collections; using System.Collections.Generic; using UnityEngine; public class TopCamer ...
- 转:Python考核试题及答案
Python测试(总分:120) 选择题(每题2分,共20分) 1.下列哪个语句在Python中是非法的? (B) A.x = y = z = 1 B.x = (y = z + 1) C.x, y = ...