操作系统实验反思

理解操作系统里面的进程调度算法,作业调度算法,存储管理,磁盘调度算法,通过c语言(加了一点c++)模拟实际调度过程

事前准备

确定好了基本思路:

  • 首先看课本,要理解相关的算法,在理解方面,作业调度里面的算法理解起来有点困难体现在:**什么时候调度作业?**最开始确定的是手动输入调度时间,找到在调度时间之前提交的作业,对这些作业进行调度。但是和老师交流后,发现调度时间并不是手动输入,而是应当在上一个作业完成时刻之后去调度。
  • 编程语言选择,因为实验报告上标注的是c/c++,所以我采用的是c语言,而没有考虑Java,事实上当老师说明可以使用Java的时候,我已经只剩下一个实验没有写,可见应当事先问清楚,搞清楚要求。
  • 所采用的方法:采用的是面向过程方法,先确定基本的数据结构,包括对相关实体的封装,然后画流程图和写伪代码,确定最基本的函数,然后确定函数的参数和返回值,最后解决函数调度次序和具体实现。在这个过程中,只要一开始理解了算法实现思路,编码并没有花太多的时间。
  • 测试数据准备:通过文件存储默认的数据,避免每次都需要输入测试数据,这在后面的测试中节约了大量的时间

实际实现过程

进程调度

没有遇到太大的困难,但是作为第一 v个实验,在构思(具体包括输入输出分析,数据结构设计,函数设计)上还是花了很多的时间。

首先确定了基本的数据结构为:链表和队列,并且可以实现其基本的操作,但是由于对c语言指针不熟悉以及一些特殊情况操作处理不足,花了很多时间在测试调试基本数据结构,总结经验如下

  1. 指针是地址,对应的是内存中的某一个存储单元,创建指针时,一定要制定 初始值,就算是空也要显示的说明为NULL;

  2. 结构体指针,特别时包含 next成员的时候,当需要独立出一个指针变量temp的时候,一定要做修改

    temp->next=NULL;
    

    否则,可以通过temp的next域访问其他节点,并不能达到独立temp指针的目的。

  3. 为结构体指针申请初始空间的时候,要显示的指定成员初始值,否则你也不知道编译器给它分配什么默认值,是一些特别奇怪的值

  4. 删除链表中指定元素考虑:链表为空(需要调用isEmpty()确定,而不能简单的使用list==NULL);删除的元素不存在;删除的元素为链表的头部,就算是维护最简单的数据结构,实现起来由于考虑不周也会产生问题。

  5. 特别是后面在实现双向队列的时候,在维护前向指针和后向指针的时候,的确花了点时间,关键是,这种基本的数据结构虽然在网上有详细的代码,但是我还是习惯自己动手实现。

借助基本数据结构及相关方法去实现具体的算法,并没有遇到太大的困难,但是由于一开始并没有考虑到的一些情况。在实现多级队列的时候,对于调度结果的输出,前面一直都正常,唯独最后一个进程在第四级队列开始执行时间和它在第三级队列执行的时间重合。这让我很郁闷?排除bug花了很长时间,发现原因在于判断进程是否执行完毕时,全局时间变量time++,导致时间对不上。进一步分析发现,不止最后一个进程时间输出有问题,前面的一些进程也有问题,问题归根于在于判断进程是否执行完毕时,全局时间变量time++。

作业调度

这一块遇到了较大的困难,主要是在理解算法上面,什么时候调度作业。是手动输入;还是自动确定调度时间。实现的第一版是按照手动输入调度时间进行的,但是不符合要求,后作出修改的时候,并没有遇到太大的阻碍,因为仅仅是修改全局事件变量time,而这个变量值的改变仅仅涉及几个主要的函数,这说明在设计函数阶段,每一个函数能够修改的变量不能过多,否则维护起来很麻烦。同时如果一个函数的功能过于复杂,要分解。在本次实验中做了如下分解:

  • 接受用户输入函数input
  • 读取相关文件内容到queue,对应函数readMessage
  • 开始调度,定义全局时间变量time,平均周转时间,带权周转时间
    • 找到time以前请求的作业findJobs到队列waitingQueue
    • 按照调度算法从waitingQueue中选取调度作业chooseJob到target
    • 执行target作业,run函数===》在后来的该动当中比较大
    • 在queue中移除target作业deleteJob
    • 计算并且更新相关时间computerAndPrintTime===》这一个函数参数很多,但是参数都属于时间这一类,因此从语义上来说,并不矛盾,在这里借用了c++里面的地址引用,其中传入函数的参数为变量地址引用
    • 判断作业是否执行完成。
  • 输出平均周转时间和带权周转时间

无论是这里,还是上面的实验,都涉及到时间变量的定义和修改,应该满足下面几点要求:

  1. 系统中某个动作产生时,涉及开始执行时间,执行时间以及结束时间。当某个动作正在执行时,时间变量将被修改,模拟时间变量修改如下:

    for(int time=startTime;time<=endTime;time++){
    	//执行一秒
    	//判断是否提前执行完毕
    }
    
  2. 处理不同动作之间的并行,将不同动作写入同一个循环

  3. startTime和endTime确定也比较麻烦,这里采用的是分别分析:

    • 初始时,startTime为第一个作业的startTime,而endTime确定比较麻烦

在写此文时,我突然想到时间time变量应该独立出来,但是这种写法不适合并行执行操作

time=1;//初始时刻
while(1){
	//执行各种各样的操作,他们都可以独立的修改time变量
	time++;
}

存储管理

这是我最得意的一个设计,整个过程下来行文流水,很顺利。无论是最后的测试结果还是中间的实现过程。我都很享受,其中令我最得意的是循环队列的设计

构思时很清楚,充分考虑了各种情况,编码环节很快乐,最后测试阶段仅仅执行了两次就通过所有的测试数据。

根据数据结构编写算法时,先确定基本的函数,实现基本函数。不过这里发生了一个小插曲,就是定位存储空间findMemory函数,根据什么查找存储区域。最开始是根据存储区域上运行的作业的名称,但是可能存在同一个作业多次申请空间,最后确定根据存储空间的开始地址和结束地址定位存储空间,的确可以标识唯一存储区域。

总结经验如下:

  1. 确定基本数据结构,编码完成之后需要测试基本功能,包括单个函数以及组合的函数

  2. 根据基本思路确定最关键的函数,分别实现函数,并测试

  3. 发现问题,运用调试解决,找到关键断点,需要使用if判断

    if(断点条件){
    	代码//在此处打断点,不要在if判断上
    }
    

磁盘调度

相当简单,真的没有遇到什么困难,想必老师会失望,因为这个实验是选做的,而且估计是最简单的!!!!
完整项目地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值