操作系统课程设计
实验一:作业调度
1、假设系统中可同时运行两道作业,给出每道作业的到达时间和运行时间,如下表所示:
2、分别用先来先服务算法、短作业优先和响应比高者优先三种算法给出作业的调度顺序。
3、计算每一种算法的平均周转时间及平均带权周转时间并比较不同算法的优劣。
程序功能:
支持从文件读入各个作业的信息(作业名,到达时间,运行时间),可以查看三种算法的作业调度顺序,以及每一个作业的周转时间和带权周转时间。同过查看三种作业调度算法的性能比较表格,比较算法的优劣。
设计思路
首先得设计一个代表进程A,B,C等的数据结构,用来保存进程的静态信息和动态信息。其次是预处理,这一步中通过读文件的方式读入进程的初始数据,生成具体的A,B,C等进程的数据结构使其能够使用进程的各种操作。
由于存在两个进程的并行,所以要设立两个cpu数据,分别表示各自的使用情况。在每次作业调度时候,选择空闲CPU使用。分别设计三个主要的功能函数来实现先来先服务、短作业优先、相应比高者优先三种算法功能,实现功能聚集。首先熟悉各个算法的思想和算法规则,分析算法的优缺点,分析算法是否存在饥饿现象。计算评价指标。周转时间等于完成时间-到达时间。带权周转时间=周转时间/运行时间。
对于FCFS算法,按照作业到达的先后顺序进行服务,考虑哪个作业先到达后备队列,是一个非抢占式算法。SJF算法,追求的是平均等待时间最短,最短的平均周转时间,最小的平均带权周转时间,是非抢占式算法。
HRRN算法是综合考虑作业的平均等待时间和要求服务的时间,每次调度时先计算每一个作业的响应比(响应比=等待时间/运行时间+1),是非抢占式算法,只有当前运行作业主动结束时,才需要调度,计算队列中每一个算法的响应比。
设计一个输出函数再设计一个算法性能的比较函数。在主函数中设计运行菜单,实现功能调用。
数据结构及算法设计
数据结构:
首先得设计一个代表进程A,B,C等的数据结构pcb,来存储到达时间,响应比,名称,运行时间,结束时间周转时间,带权周转时间,以及指向下一结构体的指针 pcb* next;
struct pcb
{
int arrive; //到达时间
double rate; //响应比
string name; //名称
int cost; //运行时间
int end; //结束时间
int turn; //周转时间
double tune_weight;
pcb* next;
};
算法设计
在执行三种算法之前,都应该执行void pre_work()进行预处理。预处理的具体过程是
将两个时钟cpu0和cpu1都置为0,周转时间置为0,平均带权周转时间也置为0.。然后读入text文件,创建一个pcb类型的头指针 pcb_head,再创建一个同样类型的t,将第一个进程A的信息读入t中,因为是第一个进程,所以响应比是1,读入后将t赋回给 pcb_head。然后循环读入文件中的其他进程。
然后回到先来先服务算法。
void fun1() {
cout << "先来先服务算法:" << endl;
pre_work();
if (gzr)cout << "进程 结束时间 周转时间 带权周转时间 " << endl;
bool flag;
for (int i = 0; i < N; i++) {
pcb* p = new pcb;
pcb* q = new pcb;
p = pcb_head;
flag = false;
q->arrive = INF;
q->next = NULL;
while (p != NULL) {
if (p->cost != 0 && p->arrive <= q->arrive && (p->arrive <= cpu0 || p->arrive <= cpu1))
{
q = p;
flag = true;
}
p = p->next;
}
if (flag == false) {
p = pcb_head;
while (p != NULL)
{
if (p->cost != 0 && p->arrive < q->arrive)q = p;
p = p->next;
}
}
if (cpu0 <= cpu1)
{
if (i == 0) cpu0 = q->arrive;
if (!flag) cpu0 = q->arrive;
cpu0 += q->cost;
q->end = cpu0;
q->turn = q->end - q->arrive; sum_turn += q->turn;
q->tune_weight = q->turn / (q->cost * 1.0); ave_turn_wei += q->tune_weight;
q->cost = 0;
out1(q);
}
else {
if (i == 1 || flag == false)cpu1 = q->arrive;
cpu1 += q->cost;
q->end = cpu1;
q->turn = q->end - q->arrive; sum_turn += q->turn;
q->tune_weight = q->turn / (q->cost * 1.0); ave_turn_wei += q->tune_weight;
q->cost = 0;
out1(q);
}
}
out_put();
}
这段代码中,定义bool类型的变量flag,如果当前进程可以在其中一个cpu中运行,flag变成true。定义两个pcb类型的指针p和q。p用来遍历当前的进程队列,循环遍历整个进程队列,找到arrive(到达时间最小)并且到达时间<=cpu0或者cpu1的时间,也就是在这两个cpu运行上一个进程结束之前或者正好结束时到达,这样尽量不会让cpu进入空闲状态。如果cpu0中的进程先完成,那么当前进程就交给cpu0来执行。否则交给cpu1。cpu的运行时间需要加上当前进程的运行时间。然后cpu运行完该进程时的总时间就是当前进程的结束时间,结束时间-到达时间得到周转时间q->turn。再周转时间/运行时间得到带权周转时间q->tune_weight。然后输出当前进程的各个信息。当第一个while循环完成后,如果flag仍然等于false,说明是两个cpu都处于空闲状态而没有进程到达。这时就选择进程中最先到达的那一个。
短作业优先算法:首先作预处理,将各个进程组成进程队列。同样是用p来遍历队列。
void fun2() {
cout << "短进程优先算法:" << endl;
pre_work();
if (gzr)cout << "进程 结束时间 周转时间 带权周转时间 " << endl;
bool flag;
for (int i = 0; i < N; i++) {
pcb* p = new pcb;
pcb* q = new pcb;
p = pcb_head;
flag = false;
q->cost = INF;
q->next = NULL;
q->arrive = INF;
while (p != NULL)
{
if (cpu0 <= cpu1 && p->arrive <= cpu0)
{
if (p->cost != 0 && p->cost <= q->cost)
{
q = p;
flag = true;
}
}
if (cpu0 > cpu1 && p->arrive <= cpu1)
{
if (p->cost != 0 && p->cost <= q->cost)
{
q = p;
flag = true;
}
}
p = p->next;
}
if (flag == false) {
p = pcb_head;
while (p != NULL)
{
if (p->cost != 0 && p->arrive < q->arrive)q = p;
p = p->next;
}
}
if (cpu0 <= cpu1)
{
if (i == 0 || !flag) cpu0 = q->arrive;
cpu0 += q->cost;
q->end = cpu0;
q->turn = q->end - q->arrive; sum_turn += q->turn;
q->tune_weight = q->turn / (q->cost * 1.0); ave_turn_wei += q->tune_weight;
q->cost = 0;
out1(q);
}
else {
if (i == 1 || flag == false)cpu1 = q->arrive;
cpu1 += q->cost;
q->end = cpu1;
q->turn = q->end - q->arrive; sum_turn += q->turn;
q->tune_weight = q->turn / (q->cost * 1.0); ave_turn_wei += q->tune_weight;
q->cost = 0;
out1(q);
}
}
out_put();
}
while (p != NULL)循环内部在找已经到达的所有进程中花费时间最小的那一个。并将其安排给cpu0和cpu1中最先空闲的那一个。flag变成true。如果if (flag == false)说明两个cpu都在等待进程来临。进程到来后,如果是第一次的进程和两个cpu都在等待进程来临这两种情况,就需要把进程的到来时间作为cpu开始工作的时间。然后cpu再加上进程运行需要花费的时间,并计算相应的周转时间,带权周转时间,平均带权周转时间。当所有进程都完成后,也就是第一层for循环完成,out函数输出数据。
高响应比优先函数:
定义pcb结构p来遍历整个队列。首先还是选择cpu0和cpu1中先有空闲的那一个。然后计算队列中进程相对于该cpu的响应比。计算完成后,判断进程是在cpu有工作的情况下到达还是cpu空闲情况下到达。如果是前者,那么就需要找到所有进程中响应比最大的那一个。如果是后者,就寻找最先到达的那一个进程。如果进程同时到达,就寻找运行时间小的那一个。找到当前最优进程,将其放入对应cpu中运行,计算其周转时间,带权周转时间,平均带权周转时间。然后输出。
程序运行情况
图1-1:先来先服务算法
图1-2:短作业优先算法
图1-3:高响应比优先算法
图1-4:各个算法性能比较
图1-5:查看各个进程的信息