实验目的
通过设计一个SPOOLING假脱机输出的模拟程序,更好地理解和掌握SPOOLING假脱机技术.。
实验内容
1.设计一个实现SPOOLING技术的进程
设计一个SPOOLING输出进程和两个请求输出的用户进程。
当用户需要输出时,调用请求输出进程,将需要输出的信息输出到输出井。
SPOOLING输出进程工作时,根据请求块记录的各进程要输出的信息,将其实际输出到显示器。这里,SPOOLING进程与请求输出的用户进程可并发运行。
2.设计进程调度算法
进程调度采用随机算法,这与进程输出信息的随机性相一致。两个请求输出的用户进程的调度概率各为45%,SPOOLING输出进程为10%,这由随机数发生器产生的随机数模拟决定。
3.数据结构
进程控制快PCB
struct pcb //进程控制块PCB
{
int id; //进程标识
int status; //状态
int length; //输出长度
int buf[BUFFERNUM];//输出缓冲
}
其中状态可用值为
0:就绪状态
1:等待状态1,表示输出井满,请求输出的用户进程必须等待
2:等待状态2,表示输出井空,SPOOLING输出进程必须等待
3:等待状态3,表示输出请求块使用完,请求输出的用户进程必须等待
4:结束状态
请求输出块
struct req
{
int reqid;//要求输出的进程
int length;//输出长度
int addr;//输出首地址
}
输出井结构
struct outbuf
{
int buf[OUTBUFFERNUM]; //输出井缓冲区
int usedNum; //输出井缓冲区已使用的数目
int head; //指示输出井空闲块首地址
//int tail; //指示输出井信息块(有信息的部分)尾地址
}
源程序
#include "stdio.h"
#include "stdlib.h"
#include "time.h"
#include "iostream.h"#define PROCESSNUM 2 //输出进程个数
#define BUFFERNUM 100 //内存缓冲字节个数
#define OUTBUFFERNUM 200 //输出井存储字节个数
#define REQBLOCKNUM 10struct pcb //进程控制块PCB
{ int id; //进程标识 int status; //状态 int length;//输出长度 int buf[BUFFERNUM];//输出缓冲
}PCB[PROCESSNUM+1]; struct req //请求输出块
{ int reqid;//要求输出的进程 int length;//输出长度 int addr;//输出首地址
}ReqBlock[REQBLOCKNUM]; struct outbuf //输出井结构
{int buf[OUTBUFFERNUM]; //输出井缓冲区int usedNum; //输出井缓冲区已使用的数目int head; //指示输出井空闲块首地址//int tail; //指示输出井信息块(有信息的部分)尾地址
}OutBuffer[PROCESSNUM];int UsedReqBlockNum=0; //记录当前已使用的请求块数目
int head=0,tail=0; //指示当前使用的输出请求块,request从tail开始取,spooling从head开始取
int FileNum[PROCESSNUM];void input()//输入函数
{for(int i=0;i<PROCESSNUM;i++){cout<<"输入第"<<i+1<<"个用户需要输出的文件数目:"; cin>>FileNum[i]; }
} void init()//初始化函数
{int i,j;for(i=0;i<PROCESSNUM;i++){OutBuffer[i].head=0;OutBuffer[i].usedNum=0;for(j=0;j<OUTBUFFERNUM;j++)OutBuffer[i].buf[j]=0;}for(i=0;i<REQBLOCKNUM;i++){ReqBlock[i].reqid=-1;ReqBlock[i].length=0;ReqBlock[i].addr=0;}for(i=0;i<PROCESSNUM+1;i++){PCB[i].id=i;PCB[i].status=0;PCB[i].length=0;for(j=0;j<BUFFERNUM;j++)PCB[i].buf[j]=0;}PCB[PROCESSNUM].status=2; //spooling进程的状态置2(输出井空)
} void request(int i)
{int j,length=0;if(PCB[i].length==0) //判断上次的输出是否处理完{FileNum[i]=FileNum[i]-1;//srand((unsigned)time(NULL));/*播种子,下面有了所以这里注释掉。。*/while(1){j=rand()%10;//随机数if((j==0)&&(length!=0)) //以0结束此次输出{PCB[i].length=length;break;}PCB[i].buf[length]=j;length++;}}if(OutBuffer[i].usedNum+length>OUTBUFFERNUM) //判断输出井是否满{PCB[i].status=1; //输出井满,进程状态置1return;}if(UsedReqBlockNum==REQBLOCKNUM) //判断是否有空闲的请求块{PCB[i].status=3; //没有空闲的请求块,进程状态置3return;}//填写请求块ReqBlock[tail].reqid=i;ReqBlock[tail].addr=OutBuffer[i].head;ReqBlock[tail].length=PCB[i].length;UsedReqBlockNum++;//将数据写到输出井int k;for(k=0;k<PCB[i].length;k++)OutBuffer[i].buf[(OutBuffer[i].head+k)%OUTBUFFERNUM]=PCB[i].buf[k];OutBuffer[i].head=(OutBuffer[i].head+PCB[i].length)%OUTBUFFERNUM;OutBuffer[i].usedNum+=PCB[i].length;PCB[i].length=0;if(PCB[PROCESSNUM].status==2) //若spooling进程阻塞,则修改其状态为可执行(0)PCB[PROCESSNUM].status=0;tail=(tail+1)%REQBLOCKNUM;if(FileNum[i]==0)PCB[i].status=4;
}void spooling()
{//请完成spooling函数的设计if(UsedReqBlockNum==0){//如果没有请求块if(PCB[0].status==4&&PCB[1].status==4){//是否所有输出进程结束PCB[2].status=4;return ;}else {PCB[2].status=2;return ;}}
//按照请求块从输出井中取数据输出(打印到屏幕)//遍历请求块int requid=ReqBlock[head].reqid;int addr=ReqBlock[head].addr;int length=ReqBlock[head].length;UsedReqBlockNum--;//将数据从输出井输出cout<<"以下为输出结果:"<<endl;int k;for(k=0;k<length;k++)cout<<OutBuffer[requid].buf[(addr+k)%OUTBUFFERNUM]<<" ";cout<<endl;OutBuffer[requid].usedNum-=length;if(PCB[0].status==3) //修改阻塞进程状态为就绪PCB[0].status=0;if(PCB[1].status==3) PCB[1].status=0;head=(head+1)%REQBLOCKNUM;}void work()//模拟进程调度
{ int i;bool isFinish;srand((unsigned)time(NULL));while(1){i=rand()%100;if(i<=45){if(PCB[0].status==0)request(0);}else if(i<=90){if(PCB[1].status==0)request(1);}elsespooling();isFinish=true;for(i=0;i<PROCESSNUM+1;i++) //判断是否所有进程都结束if(PCB[i].status!=4)isFinish=false;if(isFinish) //若所有进程都结束,则退出return;}
}
int main() //主程序
{printf("\n>>>>>>>>>>>>>>>> SPOOLing系统模拟程序 <<<<<<<<<<<<<<<<<\n");init();input();cout<<"Spooling技术将会随机从1~9分配给每个文件的缓冲区,并按照请求块的顺序将其打印"<<endl;work();return 0; }
实验结果分析
(截取程序运行结果图并进行分析和说明)
程序流程图
1)进程调度工作模拟流程
2)请求输出进程流程
3)SPOOLING输出进程流程
实验总结
(通过实验,掌握和理解的知识;实验过程中获取的知识;实验中未能解决的问题等)
加深了对数组与算法的了解。