这个学期学习操作系统,其实主要就是系统对于一些情况的应对算法,我们要做的就是写代码模拟这个情况,来了解操作系统是怎么解决的。
一、简介
进程调度是操作系统处理及管理的核心内容,调度算法为简单轮转法和优先数法。在计算机上设计进程控制块(PCB)结构,使其适用于简单轮转法和优先数调度算法。PCB通常包括以下信息:
进程标识符
连接指针
优先数 | 轮转时间片
占用的CPU时间片数
进程所需时间片数
进程状态
二、算法介绍
优先数法
用户输入:每个进程的进程标识符、进程所需时间片数、优先数
流程:
1、进程就绪队列按优先数大小从高到低排列,链首进程首先投入运行
2、进程每执行一次,进程需要的时间片数减1、该进程的优先数减3
3、若该进程执行完毕,放入完成队列,继续取出就绪队列头进程投入运行
4、若未完成,则把该进程有序插入就绪队列,取出头进程投入运行
5、重复上述操作,当所有进程都运行完毕
解释:每次取出优先级最高的进程投入运行,执行一次后接着仍是用该进程降低一级 后的优先数与就绪队列中链首进程的优先数进行比较,如果仍是该进程的优先数高或相同,便让该进程继续执行;否则,调度就绪队列的链首进程投入运行。原运行过的进程按其现 行优先数大小插入就绪队列,且改变它们对应的进程状态,一直到所有进程都运行完各自 的时间片数。
简单轮转法
用户输入:每个进程的进程标识符、进程所需时间片数、轮转时间片
流程:
1、进程就绪队列按各进程进入的先后顺序排列,取出头进程投入运行
2、每执行一次,进程所需时间片数减1,占用CPU时间片数加1
3、若进程未执行完毕,若占用CPU时间片数<轮转时间片,则该进程继续运行
4、否则则停止运行,投入就绪队列尾部,取出头进程运行
5、若进程执行完毕,则投入完成队列,从就绪队列取出头进程运行
解释:进程每次所需处理机的轮转时间片数记入进程控制块中的轮转时间片数记录项。进程执行时,每运行一个时间片,进程还需要的时间片数减1,运行进程占用处理机的时间片数加1,然后比较占用CPU的时间片数是否与该进程的轮转时间片数相等,若相等则说明已达到轮转时间,应将现运行的进程排列就绪队列的末尾,调度队列上的首进程运行,且改变它们的进程状态,直至所有进程完成各自的时间片。
三、结果
四、代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
typedef struct pcbnode
{
string name;//进程标识符
int prio;//优先数
int round;//轮转时间片
int cputime;//占用的CPU时间片数
int needtime;//进程所需时间片数
char state;//进程状态,Ready-就绪态,Run-执行态,Finish-完成态
//便于区分,等待状态用字母W
struct pcbnode *next;//连接指针
}PCB;
PCB *ready=NULL,*run=NULL,*finish=NULL;//定义三个队列,就绪队列,执行队列,完成队列
int num=5;//创建5个进程
void GetFirst();//从就绪队列取得第一个节点
void Output();//输出队列信息
void InsertPrio(PCB *in);//创建优先级队列,规定优先数越小,优先级越高
void InsertWait(PCB *in);//时间片队列
void InsertFinish(PCB *in);//时间片队列
void PrioCreate();//优先级输入函数
void TimeCreate();//时间片输入函数
void Priority();//按照优先级调度
void RoundRun();//时间片轮转调度
int main()
{
char choice;
printf("已默认为您创建了5个进程!\n");
printf("请选择调度方法(P:优先数调度 R:时间片轮转调度):");
cin>>choice;
switch(choice)
{
case 'P':
case 'p':
PrioCreate();
Priority();
break;
case 'R':
case 'r':
TimeCreate();
RoundRun();
break;
default:break;
}
Output();
return 0;
}
void GetFirst()//取得第一个就绪队列节点
{
run = ready;
if(ready!=NULL)
{
run->state = 'R';
ready = ready->next;
run->next = NULL;
}
}
void Output() /*输出队列信息*/
{
PCB *p;
p = run;
cout<<"进程名"<<'\t'<<"优先级"<<'\t'<<"轮数"<<'\t'<<"cpu时间"<<'\t'<<"需要时间进程状态"<<endl;
while(p!=NULL)
{
cout<<p->name<<'\t'<<p->prio<<'\t'<<p->round<<'\t'<<p->cputime<<'\t'<<p->needtime<<'\t'<<p->state<<'\t'<<endl;
p = p->next;
}
p = ready;
while(p!=NULL)
{
cout<<p->name<<'\t'<<p->prio<<'\t'<<p->round<<'\t'<<p->cputime<<'\t'<<p->needtime<<'\t'<<p->state<<'\t'<<endl;
p = p->next;
}
p = finish;
while(p!=NULL)
{
cout<<p->name<<'\t'<<p->prio<<'\t'<<p->round<<'\t'<<p->cputime<<'\t'<<p->needtime<<'\t'<<p->state<<'\t'<<endl;
p = p->next;
}
}
void InsertPrio(PCB *in)//按进程优先级插入到就绪队列
{
PCB *node1,*node2;
node1 = node2 = ready;
if(ready == NULL)//如果队列为空,则为第一个元素
{
in->next = ready;
ready = in;
}
else
{
if(in->prio >= node1->prio)//比第一个还要大,则插入到队头
{
in->next = ready;
ready = in;
}
else
{
while(node1->next != NULL)//移动指针查找它第一个大于等于优先级的位置
{
node2 = node1;
node1 = node1->next;
if(in->prio >= node1->prio)break;
}//此时in的优先级>=node1的优先级
if(in->prio >= node1->prio)
{
in->next = node1;
node2->next = in;
}
else
{
in->next = node1->next;
node1->next = in;
}
}
}
}
void InsertWait(PCB *in)//将进程直接插入到就绪队列尾部
{
PCB *node1;
node1 = ready;
if(ready == NULL)
{
in->next = ready;
ready = in;
}
else
{
while(node1->next != NULL)
{
node1 = node1->next;
}
in->next = node1->next;
node1->next = in;
}
}
void InsertFinish(PCB *in)//将进程插入到完成队列尾部
{
PCB *node1;
node1 = finish;
if(finish == NULL)
{
in->next = finish;
finish = in;
}
else
{
while(node1->next != NULL)
{
node1 = node1->next;
}
in->next = node1->next;
node1->next = in;
}
}
void PrioCreate()//优先级调度输入函数
{
int i;
printf("输入进程名字 所需时间 优先级:\n");
for(i = 0;i < num; i++)
{
PCB *tmp = new PCB;
cin >>tmp->name >> tmp->needtime >> tmp->prio;
tmp->state = 'W';
tmp->round = 0;
tmp->cputime = 0;
InsertPrio(tmp);//按照优先级从高到低,插入到就绪队列
}
}
void TimeCreate()//时间片输入函数
{
int i;
printf("输入进程名字 所需时间 轮转时间片数:\n");
for(i = 0;i < num; i++)
{
PCB *tmp = new PCB;
cin>>tmp->name>>tmp->needtime>>tmp->round;
tmp->state ='W';
tmp->prio = 0;
tmp->cputime = 0;
InsertWait(tmp);
}
}
void Priority()//按照优先级调度,每次执行一个时间片
{
int flag = 1;
GetFirst();
while(run != NULL)//当就绪队列不为空时,则调度进程如执行队列执行
{
Output();//输出每次调度过程中各个节点的状态
while(flag)
{
run->prio -= 3;//优先级减去三
run->needtime--;//进程执行完成的剩余时间减一
run->cputime++;//CPU时间片加一
if(run->needtime == 0)//如果进程执行完毕,将进程状态置为F,将其插入到完成队列
{
run->state = 'F';
InsertFinish(run);
flag = 0;
}
else//将进程状态置为W,入就绪队列
{
run->state = 'W';
InsertPrio(run);
flag = 0;
}
}
flag = 1;
GetFirst();//继续取就绪队列队头进程进入执行队列
}
}
void RoundRun()//时间片轮转调度算法
{
int flag = 1;
GetFirst();
while(run != NULL)
{
Output();
while(flag)
{
run->cputime++;
run->needtime--;
if(run->needtime == 0)//进程执行完毕
{
run->state = 'F';
InsertFinish(run);
flag = 0;
}
else if(run->cputime == run->round)//时间片用完
{
run->state = 'W';
run->cputime = 0;//计数器清零,为下次做准备
InsertWait(run);
flag = 0;
}
}
flag = 1;
GetFirst();
}
}