操作系统原理 实验1 《CPU Scheduling》

操作系统原理 实验1 《CPU Scheduling》

>>本实验源码

一、实验目的

多道系统中,当就绪进程数大于处理机数时,须按照某种策略决定哪些进程优先占用处理机。本实验模拟实现处理机调度,加深了解处理机调度的工作过程。

二、实验内容

选择一个调度算法,实现处理机调度:
1、设计一个按优先权调度算法实现处理机调度的程序;
2、设计按时间片轮转实现处理机调度的程序。

三、实验方法

1、构建进程PCB,PCB内容包括:
\qquad 进程名/PID;
\qquad 要求运行时间(单位时间);
\qquad 优先权;
\qquad 状态;
\qquad PCB指针;
2、设置后备队列和挂起队列,设计作业调度算法、进程调度算法,以及挂起、解挂功能;
3、采用图形界面,动态展示调度过程中各进程及队列变化。

四、实验步骤

1、选定程序开发环境

\qquad Qt Creator 4.2.1(Qt 5.8.0)
\qquad 图形化界面编程使用的编程语言:C++

2、明确功能(需求分析)

\qquad 先做优先级(动态优先级)调度模式下的CPU调度模拟程序,并限制道数为6。展示内存中ready、running和挂起(suspended)状态下的各个进程,动态展示CPU根据特定算法调度各个进程的流程,提供挂起、解挂、查看后备队列、添加作业(进入后备队列)、查看进程信息、开始调度和终止调度的功能接口并进行实现。

3、设计数据结构

(1) 进程应该包括两个类,一个是进程类,其中进程类的数据域应该包括一个PCB类的指针,另一个就是PCB类,PCB类中进程名/PID以字符串形式存储,其他均以int整型形式存储(PCB指针为PCB类的对象指针)。
(2) 后备队列由于不进主存,可以不在界面上进行展示,因此可以存储在数据库中(实现不限作业个数),这里使用MySQL数据库。
(3) 由于道数限制为6,在内存中的进程可以用大小为6的对象数组进行存储而非指针(避免反复进行new操作申请内存空间和delete操作减少系统资源消耗)。
(4) ready队列中的进程数目不确定,因此使用进程指针类型的指针数组(大小6)对ready队列中的进程(其指针)进行存储,同理suspended队列也考虑使用指针数组。
(5) ready队列及其操作应该是一系列的函数组成(但是suspended队列只有挂起、解挂两种操作,后备队列只有添加、删除操作),因此将ready队列单独写成一个readyque类进行封装。
(6) 添加作业、查看进程信息、选择挂起的进程因为都是要单独进行展示的小窗口,因此利用qt的多界面进行封装,各自写成单独的模块。同理,后备队列也是一个单独的展示模块,因此封装成backupque类。
(7) 主界面widget,包括ready队列类对象、后备队列类对象、选择挂起进程类对象,各类状态控制阀(bool类型变量组成),循环驱动器(int类型的计时器ID变量组成),对象数组(大小6),挂起指针数组(大小6),进程总数计数器(int)以及移动进程(被调度的对象)指针。
(8) 主函数main()把主界面new出来后,进入事件循环,程序开始运行。

4、设计各类操作(写成类内函数封装实现)

(1) 进程类(SProcess类)与进程控制块类(PCB类):

- 进程初始化:包括进程信息的初始化,进程对PCB的设置;
- 进程信息的访问与改变:主要是各个数据域的访问器与修改器;
- PCB初始化:PCB类的构造函数;
- PCB信息的访问与改变:各个数据域的访问器与修改器。

(2) 后备队列类(BackUpQue类)

- 初始化队列:调取数据库中的记录,将数据填入展示的表格;
- 刷新展示表格:清空表格内容,重新初始化。

(3) 就绪(ready)队列(ReadyQue类)

- ready队列初始化与刷新:包括初始化展示的按钮、初始化信息展示界面;
- ready队列存储数组的增删操作;
- ready队列展示按钮的增删操作,信息修改操作;
- ready队列所有进程按照优先级排序操作;
- 各个数据域的访问器与修改器;
- ready队列进程优先级的修改操作。

(4) 进程信息展示类(ReadyInfoDialog类)

- 根据指定的进程指针显示进程相关信息。

(5) 添加作业类(AddWorks类)

- 重置用户输入的内容;
- 提交功能,将用户指定的作业信息包装成一条记录插入数据库;

(6) 主界面类(Widget类)

- 驱动器、挂起队列、作业调度的初始化,界面区域的初始化分配;
- 驱动器的暂停(停止)与开始;
- 作业调度监听,将后备队列中的队首作业调入内存(进ready队列);
- 动画(移动效果)函数及其相关的函数;
- 进程running状态处理(包括动态优先级的处理);
- CPU调度函数,从ready队列中调度进程进入running状态;
- 进程终止运行函数(出内存);
- 进程结束running状态进入ready状态的调度;
- (选)时间片轮转、抢占监听;

5、确定关键策略

(1) 优先权级调度
每次进行CPU调度之前对存储ready队列进程指针的容器按照优先权级进行排序,选取最高优先级(假设从大到小排序,那么每次出ready队列的就是下标为0的数组元素)的进程指针出ready队列进入running状态进程处理。

(2) CPU调度事件循环
这里一开始没想到很好的方法,并且考虑到自己对QThread多线程编程很不了解,因此选择了多个计时器的计时器事件实现循环CPU调度,对每个关键过程设定计时器,在很小的时间间隔内频繁调用,再设定状态值,只有状态值符合要求该函数才会执行,否则返回。最后只需要改变状态值即可实现过程的过渡与切换。

(3) 时间片轮转调度
考虑到排序等一系列函数都集中在ready队列类中(一开始设计失误),打算实现基于优先级调度的时间片轮转调度,设置时间片模式开关。

(4) 抢占监听
这个很好实现,多加一个计时器,时刻判断是否符合抢占条件(比较ready队列队首进程的优先级与正在运行的进程的优先级),如果符合则修改状态值即可。

6、编写程序实现上述功能,并进行界面的优化整理

五、实验结论

不同的CPU调度算法有不同的特点,各有各的优势,比如单纯的优先级算法,可以优先处理急需处理的进程,提高效率,但是存在饥饿问题,引入动态优先级调配模块之后可以有效地减少饥饿;时间片轮转算法不存在饥饿问题,但是由于时间片的选取可能造成调度过于频繁的问题,效率不高;同理在动态优先级情况下的抢占模式,一方面可以及时处理重要的进程,但是另一方面也可能造成调度次数过于频繁的问题。

六、实验小结

通过GUI编程对CPU调度的流程进行可视化的模拟演示,加深了自己对于CPU优先级调度、时间片轮转调度这几种调度算法的理解,同时也提高了自己的GUI编程能力。因为自己决定使用动画效果演示,因此实验给我最大的难点就是无法在不使用多线程的情况下使得程序不停地循环CPU调度这个流程,经过不断的思考才想出了使用多个计时器不停调用函数这个效率低下的“笨办法”,写完之后才发现可以不用每个计时器都去调用对应函数,只需要在事件函数中添加判断,然后不断监听调度的开始与结束状态即可。并且本身实验程序的设计扩展性不强,导致后来只能在优先级的基础上添加时间片轮转调度,而不能将二者完完全全分离开来,这也是之后设计时要注意的问题。

作者按:第二个实验是基于第一个实验来编写的,因此实验展示、源码的最终版本均集中在实验2。

大致的演示:
在这里插入图片描述

  • 7
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值