操作系统概论实验指导书实验一进程管理.docx
《操作系统概论实验指导书实验一进程管理.docx》由会员分享,可在线阅读,更多相关《操作系统概论实验指导书实验一进程管理.docx(15页珍藏版)》请在冰豆网上搜索。
操作系统概论实验指导书实验一进程管理
实验一进程管理
一、目的
进程调度是处理机管理的核心内容。
本实验要求编写和调试一个简单的进程调度程序。
通过本实验加深理解有关进程控制块、进程队列的概念,并体会和了解进程调度算法的具体实施办法。
二、实验内容及要求
1、设计进程控制块PCB的结构(PCB结构通常包括以下信息:
进程名(进程ID)、进程优先数、轮转时间片、进程所占用的CPU时间、进程的状态、当前队列指针等。
可根据实验的不同,PCB结构的内容可以作适当的增删)。
为了便于处理,程序中的某进程运行时间以时间片为单位计算。
各进程的轮转时间数以及进程需运行的时间片数的初始值均由用户给定。
2、系统资源(r1…rw),共有w类,每类数目为r1…rw。
随机产生n进程Pi(id,s(j,k),t),0<=i<=n,0<=j<=m,0<=k<=dt为总运行时间,在运行过程中,会随机申请新的资源。
3、每个进程可有三个状态(即就绪状态W、运行状态R、等待或阻塞状态B),并假设初始状态为就绪状态。
建立进程就绪队列。
4、编制进程调度算法:
时间片轮转调度算法
本程序用该算法对n个进程进行调度,进程每执行一次,CPU时间片数加1,进程还需要的时间片数减1。
在调度算法中,采用固定时间片(即:
每执行一次进程,该进程的执行时间片数为已执行了1个单位),这时,CPU时间片数加1,进程还需要的时间片数减1,并排列到就绪队列的尾上。
三、实验环境
操作系统环境:
Windows或DOS系统。
编程语言:
TurboC、VisualC++、brolandC++、VisualBasic、Delphi、Java等。
四、实验思路和设计
1、程序流程图
由学生自行完成。
2、主要程序代码
//PCB结构体
structpcb{
intid;//进程ID
intra;//所需资源A的数量
intrb;//所需资源B的数量
intrc;//所需资源C的数量
intntime;//所需的时间片个数
intrtime;//已经运行的时间片个数
charstate;//进程状态,W(等待)、R(运行)、B(阻塞)
structpcb*next;
}*hready=NULL,*hblock=NULL,*p;//hready,hblock分别为指向就绪和阻塞队列
typedefstructpcbPCB;
intm,n,r,a,b,c,h=0,i=1,time1Inteval;//m为要模拟的进程个数,n为初始化进程个数
//r为可随机产生的进程数(r=m-n)
//a,b,c分别为A,B,C三类资源的总量
//i为进城计数,i=1…n
//h为运行的时间片次数,time1Inteval为时间片大小(毫秒)
//将进程插入到队列链尾(包括就绪队列和阻塞队列)
PCB*insert(PCB*head,PCB*pcb)//带两个指针形参:
队列指针head和当前进程PCB
{
PCB*pi,*p1;
p1=head;
pi=pcb;
if(head==NULL)
{
head=pi;
pi->next=NULL;
}
else
{
while(p1->next!
=NULL)
{p1=p1->next;}
p1->next=pi;
pi->next=NULL;
}
return(head);
}
//对进程进行初始化,建立就绪队列、阻塞队列。
voidinput()
{
AnsiStringstr1;
m=StrToInt(Form1->Edit1->Text);//读取要模拟的进程总数给m
n=StrToInt(Form1->Edit2->Text);//读取需初始化进程数给n
a=StrToInt(Form1->Edit3->Text);//读取A类资源的总数给a
b=StrToInt(Form1->Edit4->Text);//读取B类资源的总数给b
c=StrToInt(Form1->Edit5->Text);//读取C类资源的总数给c
time1Inteval=StrToInt(Form1->Edit6->Text);//读取时间片长度给time1Inteval
Form1->Timer1->Interval=time1Inteval;
r=m-n;//计算可随机产生的进程数为r
for(i=1;i<=n;i++)//初始化n个进程信息
{
p=getpcb(PCB);//#definegetpcb(type)(type*)malloc(sizeof(type))
p->id=i;
str1+="产生进程ID:
";str1+=IntToStr(p->id);str1+="\r\n";
p->ra=(random(a-3)+3);
str1+="所需A类资源数:
";str1+=IntToStr(p->ra);str1+="\r\n";
p->rb=(random(b));
str1+="所需B类资源数:
";str1+=IntToStr(p->ra);str1+="\r\n";
p->rc=(random(c-2)+2);
str1+="所需C类资源数:
";str1+=IntToStr(p->ra);str1+="\r\n";
p->ntime=(random(5)+1);
str1+="所需时间片个数:
";str1+=IntToStr(p->ntime);str1+="\r\n";
p->rtime=0;
p->next=NULL;
if(((a-(p->ra))>=0)&&((b-(p->rb))>=0)&&((c-(p->rc))>=0))//如果资源符合所需要求
{//则写入就绪队列队尾(状态为W)
a=a-(p->ra);//当前所剩A类资源数目
b=b-(p->rb);//当前所剩B类资源数目
c=c-(p->rc);//当前所剩C类资源数目
p->state='W';
hready=insert(hready,p);//将进程插入就绪队列
}//if
else//如果资源不符合所需要求,则写入阻塞队列队尾(状态为B)
{
p->state='B';
hblock=insert(hblock,p);
}//if
str1+="当前进程状态:
";
str1+=(p->state);
str1+="\r\n";
str1+="\r\n";
}//for
Form1->Memo1->Lines->Add(str1);
}
//从链表起始地址开始输出该链表的内容
voiddisp(PCB*head)
{PCB*p1;
p1=head;
AnsiStringstr2;
if(head!
=NULL)//链表非空
{
do
{
str2+="";
str2+=IntToStr(p1->id);str2+="";
str2+=(p1->state);str2+="";
str2+=IntToStr(p1->ra);str2+="";
str2+=IntToStr(p1->rb);str2+="";
str2+=IntToStr(p1->rc);str2+="";
str2+=IntToStr(p1->ntime);str2+="";
str2+=IntToStr(p1->rtime);str2+="\r\n";
p1=p1->next;
}while(p1!
=NULL);//不断输出进程的信息,直到链尾!
}//if
else
{str2+="\t\t该队列中没有进程!
\r\n";}
Form1->Memo1->Lines->Add(str2);
}
//输出就绪队列和阻塞队列的信息
voidoutputall()
{
AnsiStringstr1,str2,str3;
str3+="\r\n";
str3+="===============CPU时间片运行了:
";
str3+=IntToStr(h);
str3+="次===============\r\n";
Form1->Memo1->Lines->Add(str3);
str1+="*********************************当前就绪队列的信息";
str1+="*********************************\r\n";
str1+="进程ID进程状态A资源数B资源数C资源数需要时间片已运行时间片";
Form1->Memo1->Lines->Add(str1);
disp(hready);
str2+="*********************************当前阻塞队列的信息";
str2+="*********************************\r\n";
str2+="\r\n";
str2+="进程ID进程状态A资源数B资源数C资源数需要时间片已运行时间片";
Form1->Memo1->Lines->Add(str2);
disp(hblock);
}
//建立一个PCB结构体型的空链表
PCB*increat(void)
{PCB*head;
head=NULL;
return(head);
}
//运行就绪队列的头进程,运行一个时间片,轮转一个时间片,时间片轮转调度算法
PCB*running(PCB*head)
{
PCB*p1;
p1=head;
AnsiStringstr4;
If(p1->next==NULL)head=increat();
else{head=p1->next;}
p1->state='R';//进程状态由就绪转向运行
(p1->rtime)++;//已运行时间片数增加1
h++;
str4+="~~~~~~~~~~~~~~~~当前正在运行的进程ID是:
";
str4+=IntToStr(p1->id);
str4+="~~~~~~~~~~~~~~~~~~\r\n";
str4+="进程ID进程状态A资源数B资源数C资源数需要时间片已运行时间片\r\n";
str4+="";
str4+=IntToStr(p1->id);str4+="";
str4+=(p1->state);str4+="";
str4+=IntToStr(p1->ra);str4+="";
str4+=IntToStr(p1->rb);str4+="";
str4+=IntToStr(p1->rc);str4+="";
str4+=IntToStr(p1->ntime);str4+="";
str4+=IntToStr(p1->rtime);str4+="";
Form1->Memo1->Lines->Add(str4);
if(p1->ntime==p1->rtime)//如果已经运行的时间片到达所需次数,该进程结束
{
str4+="\r\n\r\n\t\tID号为:
";
str4+=IntToStr(p1->id);
str4+="的进程已经完成!
!
!
";
Form1->Memo1->Lines->Add(str4);
a=a+(p1->ra);
b=b+(p1->rb);
c=c+(p1->rc);
free(p1);//释放当前指针
}
else//如果已经运行的时间片未到达所需次数,该进程运行一个时间片后进入就绪队列尾
{
p1->state='W';
head=insert(head,p1);
}
return(head);
}
//检测当前资源数目是否满足阻塞队列里进程的需求
voidtestblock()
{
PCB*p1,*p2;
p1=hblock;
p2=hblock;
AnsiStringstr5;
while((hblock!
=NULL)&&(p1!
=NULL))
{
if((a-(p1->ra)>=0)&&(b-(p1->rb)>=0)&&(c-(p1->rc)>=0))//如果满足
{if(p1==hblock)
{
hblock=p1->next;
p1->state='W';
hready=insert(hready,p1);//将阻塞的进程插入就绪队列
a=a-(p->ra);
b=b-(p->rb);
c=c-(p->rc);
str5="\tID号为:
";
str5+=IntToStr(p1->id);
str5+="的进程由阻塞队列转入就绪队列!
\r\n";
p1=hblock;
}//if(p1==hblock)
else
{p2->next=p1->next;
p1->state='W';
hready=insert(hready,p1);
str5="\tID号为:
";
str5+=IntToStr(p1->id);
str5+="的进程由阻塞队列转入就绪队列!
\r\n";
p1=p2->next;
}//else
}//大if
else
{p2=p1;
p1=p1->next;
}//else
Form1->Memo1->Lines->Add(str5);
}//whlie
}
//检测是否有新的进程产生,随机产生新进程
voidtestnew()
{
intt;
AnsiStringstr6;
if(r>0)//r=m-n为可随机产生的进程数目
{
t=random(9);//生成随机数
if(t<=7)//如果随机数小于等于7,则产生新进程,否则不产生
{
p=getpcb(PCB);
str6+="有新的进程申请加入:
\r\n";
p->id=i++;//i为全程变量,表示进程号?
str6+="进程ID:
";
str6+=IntToStr(p->id);
str6+="\r\n";
p->ra=(random(a-3));//随机分配资源
str6+="所需A类资源数:
";
str6+=IntToStr(p->ra);
str6+="\r\n";
p->rb=(random(b-3));
str6+="所需B类资源数:
";
str6+=IntToStr(p->rb);
str6+="\r\n";
p->rc=(random(c-3));
str6+="所需C类资源数:
";
str6+=IntToStr(p->rc);
str6+="\r\n";
p->ntime=(random(5)+1);//随机分配时间片总数
str6+="所需时间片个数:
";
str6+=IntToStr(p->ntime);
str6+="\r\n";
p->rtime=0;//已运行时间片数初始为0
p->next=NULL;
if(((a-(p->ra))>=0)&&((b-(p->rb))>=0)&&((c-(p->rc))>=0))
{//进程满足要求,进入就绪队列
a=a-(p->ra);//分配资源给该进程,总资源数减少
b=b-(p->rb);
c=c-(p->rc);
p->state='w';
str6+="当前进程状态:
";
str6+=(p->state);
str6+="\r\n";
hready=insert(hready,p);
str6+="资源满足新进程需求,该进程进入就绪队列!
";
}//if
else//进程不满足要求,进入阻塞队列
{
p->state='B';
hblock=insert(hblock,p);
str6+="当前进程状态:
";
str6+=(p->state);
str6+="\r\n";
str6+="资源不能满足新进程需求,该进程进入阻塞队列!
";
}//else
}//if(t<=7)
Form1->Memo1->Lines->Add(str6);
}//if(r>0)
r--;
}
//系统三类资源变化情况的显示
voidrescore()
{
if(a>a1){Form1->Edit7->Text=IntToStr(a1);}
if(a<0){Form1->Edit7->Text=0;}
if(a>=0&&aEdit7->Text=IntToStr(a);}
if(b>b1){Form1->Edit8->Text=IntToStr(b1);}
if(b<0){Form1->Edit8->Text=0;}
if(b>=0&&b<=b1){Form1->Edit8->Text=IntToStr(b);}
if(c>c1){Form1->Edit9->Text=IntToStr(c1);}
if(c<0){Form1->Edit9->Text=0;}
if(c>=0&&c<=c1){Form1->Edit9->Text=IntToStr(c);}
}
//时间片轮转调度算法(先来先服务FCFS算法)
voidrunFcfs()
{
AnsiStringstr;
if(form1_hready!
=NULL)//如果就绪队列为非空,则不断运行,直到就绪队列为空为止
{
outputall();//输出就绪队列和阻塞队列的信息
form1_hready=running(form1_hready);//将就绪队列的第一个进程运行一个时间片
testblock();//检查阻塞队列是否有进程可以进入就绪队列
testnew();//检查是否有新进程产生
rescore();//系统三类资源变化情况的显示
}
else
{
Form1->Timer1->Enabled=false;
Form1->Edit7->Text=IntToStr(a1);
Form1->Edit8->Text=IntToStr(b1);
Form1->Edit9->Text=IntToStr(c1);
str+="\r\n\r\n<<<<<<<<<<<<<<<所有的进程都已经成功运行结束!
>>>>>>>>>>>>>>";
Form1->Memo1->Lines->Add(str);
}
}
//计时器触发时间片轮转调度算法
void__fastcallTForm1:
:
Timer1Timer(TObject*Sender)
{
runFcfs();//调度算法
}
//将结果保存成txt文件
void__fastcallTForm1:
:
N8Click(TObject*Sender)
{
if(Form1->SaveDialog1->Execute())
{
FILE*fp=fopen(Form1->SaveDialog1->FileName.c_str(),"w");
if(fp==NULL)
{
MessageBox(NULL,"打开文件出错","信息",MB_OK);
return;
}
for(inti=0;iMemo1->Lines->Count;i++)
{fputs(Form1->Memo1->Lines->Strings[i].c_str(),fp);
fputc('\n',fp);
}
fclose(fp);
}
}
//开始模拟按钮单击执行函数
void__fastcallTForm1:
:
Button1Click(TObject*Sender)
{
runmain();
Form1->Button1->Enabled=false;
Form1->Edit1->Enabled=false;
Form1->Edit2->Enabled=false;
Form1->Edit3->Enabled=false;
Form1->Edit4->Enabled=false;
Form1->Edit5->Enabled=false;
Form1->Edit6->Enabled=false;
}
//清除屏幕按钮单击执行函数
void__fastcallTForm1:
:
Button2Click(TObject*Sender)
{
Form1->Memo1->Clear();
Button1->Enabled=true;
h=0;
Form1->Edit1->Enabled=true;
Form1->Edit2->Enabled=true;
Form1->Edit3->Enabled=true;
Form1->Edit4->Enabled=true;
Form1->Edit5->Enabled=true;
Form1->Edit6->Enabled=true;
}
//运行的主函数
voidrunmain()
{
AnsiStringstr,str1;
input();//对进程进行初始化,建立就绪队列、阻塞队列。
Form1->Timer1->Enabled=true;//触发时钟,调用runFCFS,开始时间片轮转调度算法。
str+="\r\n";
}
3、运行界面和运行结果
界面中,可以任意设定需要模拟的进程总数(如5),初始化进程个数(如3),还有A、B、C三类资源的总数(如10、10、10)。
为了方便显示,还可以设定时间片的长度(如500毫秒)。
除此之外,在运行过程中,所有的资源都是随机生成的,并且其中新进程的产生也是随机的,但是产生的进程总数不会多于开始设定的模拟的进程总数,以防止不断产生新进程,程序不断运行。
在显示窗口的上方,还会实时显示资源的变化情况,方便对运行的观察。
当运行结束后,可以通过工具栏中的显示选项中的保存结果按钮,将结果保存成txt文件格式,方便运行后的结果分析。