题目:
实现对SPOOLING输出模拟系统。具体实现要求如下:(不局限下述情况,在工作量不缩减的情况下,可行设计实现过程。)
(1)包括一个SPOOLING输出进程和一个SPOOLING输出请求服务程序以及两个请求输出的进程。
(2)请求输出进程每次调用请求服务程序输出一行信息,由输出请求服务程序将该信息项送如输出井。待输出一个结束标志时,表示一个输出文件输出完成,在输出井中形成一个输出信息块,并构成一个输出请求块,SPOOLING输出进程工作时,根据某输出请求块将输出井中相应信息块实际输出到打印机或CRT,SPOOLING进程与请求输出进程可并发运行。
(3)进程调度采用随机调度法,这与进程的输出的随机性相一致。两个请求输出进程的调度概率各为45%,SPOOLING输出进程为10%,这由产生随机数来模拟。
(4) 为进程设置三种基本运行状态:可执行、等待和结束。等待状态又可分成等待状态1和等待状态2。状态变换的条件如下:
①进程执行完毕后置成“结束态”。
②服务程序在输出信息时,如发现输出井已满,将调用进程置成“等待状态1”。
③SPOOLING进程在输出井空时进入“等待状态2”。
④SPOOLING进程输出一个信息块后,应释放该信息块所占用的输出井空间,并将正在等待输出的进程置为“可执行态”。
⑤ 服务程序在输出信息到输出井并形成信息块后,将SPOOLING进程置成“可执行态”。
流程图分析:
(1)进程调度工作模拟流程:
(2)请求输出进程流程
(3)SPOOLING输出进程流程
实现代码:
#include <iostream>
#include "stdio.h"
#include "stdlib.h"
#include "time.h"
using namespace std;
#define PROCESSNUM 2 //两个请求输出的进程
#define BUFFERNUM 100 //内存缓冲字节个数
#define OUTBUFFERNUM 200 //输出井存储字节个数
#define REQBLOCKNUM 10 //定义请求块个数
//0:可执行态:SPOOLING进程输出一个信息块后,应释放该信息块所占用的输出井空间,并将正在等待输出的进程置为“可执行态”。;
//服务程序在输出信息到输出井并形成信息块后,将SPOOLING进程置成“可执行态”
//1:等待状态1,表示输出井满,请求输出的用户进程必须等待,将调用进程设置为“等待状态1”。
//2:等待状态2,表示输出井空,SPOOLING输出进程必须等待
//3:等待状态3,表示输出请求块使用完,请求输出的用户进程必须等待
//4:结束态:进程执行完毕
struct 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()//初始化函数
//对各进程的PCB、输出请求块、输出并初始化
{
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;
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; //等待状态1,表示输出井满,请求输出的用户进程必须等待
return;
}
if (UsedReqBlockNum == REQBLOCKNUM) //判断是否有空闲的请求块
{
PCB[i].status = 3; //没有空闲的请求块,进程状态置3,
return;
}
//填写请求块
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输出进程流程
{
//完成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);
}
else
spooling();
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;
}
解释说明:
0:可执行态:SPOOLING进程输出一个信息块后,应释放该信息块所占用的输出井空间,并将正在等待输出的进程置为“可执行态”;服务程序在输出信息到输出井并形成信息块后,将SPOOLING进程置成“可执行态”
1:等待状态1,表示输出井满,请求输出的用户进程必须等待,将调用进程设置为“等待状态1”。
2:等待状态2,表示输出井空,SPOOLING输出进程必须等待
3:等待状态3,表示输出请求块使用完,请求输出的用户进程必须等待
4:结束态:进程执行完毕