题目 SP00LING假脱机输入输出技术模拟
1.设计一个实现SP001ING技术的进程
要求设计一个SP00LING输出进程和两个请求输出的用户进程,以及一个SP00LING输出服务程序。当请求输出的用户进程希望输出一系列信息时,调用输出服务程序,由输出服务程序将该信息送入输出井。待遇到一个输出结束标志时,表示进程该次的输出文件输出结束。之后,申请一个输出请求块(用来记录请求输出的用户进程的名字、信息在输出井中的位置、要输出信息的长度等),等待SP00LING进程进行输出。
SP00LING输出进程工作时,根据请求块记录的各进程要输出的信息,将其实际输出到打印机或显示器。这里,SP00LING输出进程与请求输出的用户进程可并发运行。
2.设计进程调度算法
进程调度采用随机算法,这与进程输出信息的随机性相一致。两个请求输出的用户进程的调度概率各为45%,SP00LING输出进程为10%,这由随机数发生器产生的随机数来模拟决定。
3.进程状态
进程基本状态有3种,分别为可执行、等待和结束。可执行态就是进程正在运行或等待调度的状态;等待状态又分为等待状态1、等待状态2和等待状态3。
状态变化的条件为:
①进程执行完成时,置为“结束”态。
②服务程序在将输出信息送输出井时,如发现输出井已满,将调用进程置为“等待状态1”。
③SP00LING进程在进行输出时,若输出井空,则进入“等待状态2”。
④SP00LING进程输出一个信息块后,应立即释放该信息块所占的输出井空间,并将正在等待输出的进程置为“可执行状态”。
⑤服务程序在输出信息到输出井并形成输出请求信息块后,若SP00LING进程处于等待态,则将其置为“可执行状态”。
⑥当用户进程申请请求输出块时,若没有可用请求块时,调用进程进人“等待状态3”。
4.数据结构
①进程控制块PCB
struct pcb
{int id; /进程标识数/
Int status; /进程状态/
Int count: /要输出的文件数/
Int x: /进程输出时的临时变量/
}PCB[3];
status=
其中,
0为可执行态;
1为等待状态1,表示输出井满,请求输出的用户进程等待;
2为等待状态2,表示请求输出井空,SP00LING输出进程等待;
3为等待状态3,表示请求输出井满,请求输出的用户进程等待;
4为结束态,进程执行完成。
②请求输出块reqblock
struct{
int reqname; /请求进程名/
int length; /本次输出信息长度/
int addr; /信息在输出井的首地址/
} reqblock:[10];
③输出井BUFFER
SP00LING系统为每个请求输出的进程在输出井中分别开辟一个区。本实验可设计一个二维数组(int buffer[2][100])作为输出井。每个进程在输出井最多可占用100个位置。
5.编程说明
为两个请求输出的用户进程设计两个输出井。每个井可存放100个信息,即buffer[2][100]。为此,设计两个计数器,使用数组C1[2],分别表示两个用户进程可使用的输出井的空间。其初值c1[0],c1[1]都为100。用C2[2][2]二维指针数组表示输出井使用情况。C2[0][0]代表buffer[0]的第一个可用空缓冲指针,C2[0][1]代表buffer[0]的第一个满缓冲指针;C2[1][0]代表buffer[1]的第一个可用空缓冲指针,C2[1][1]代表buffer [1]的第一个满缓冲指针。
每个用户进程请求输出文件的个数由用户从键盘输入而定。当用户进程将其所有文件输出完时,终止运行。
为简单起见,用户进程简单地设计成:每运行一次,随机输出数字0~9之间的一个数,且用0作为文件结束标志。当输出值为零时,就形成一个请求信息块,填入请求输出信息块reqblock结构中。这个输出请求块结构也有一个计数器C3,表示当前系统剩余的请求输出信息块个数,初值为10。
另外,再设两个指针Pt1和Ptr2表示请求输出块使用情况。Ptr1是要输出的第一个请求输出块指针,初值为0;Ptr2是空闲请求输出块指针,初值也为0。两个指针按模10进行变化,即把请求输出块结构数组看成是一个环型数组。根据Ptr1和Ptr2的变化,确定请求输出块的使用情况。
主程序中包括(或调用)调度程序。调度程序中包括一个随机数函数,以该函数值为依据,按照如图1所示框图调度3个进程。完成对各数据结构的初始化。
6.程序框图
(1)SP00LING输出模拟系统主控流程图如图1所示。
图1 SP00LING输出模拟系统主控流程图
(2)SP00LING输出服务程序由请求输出的两个用户进程调用,程序流程图如图2所示。
图2 输出请求服务的程序框图
(3)SPOOLING输出进程流程图如图3所示。
图3 SP00LING输出进程流程图
(ps.以上问题描述和流程图只是课设老师给的,本人在具体编程中做了些许改动)
//语言:c++
//编译器:vs2019
#include "time.h"
#include <iostream>
using namespace std;
struct pcb //进程控制块PCB
{
int id; //进程标识
int status; //状态0为可执行态;1为等待状态1,表示输出井满,请求输出的用户进程等待;2为等待状态2,表示请求输出井空,SP00LING输出进程等待;3为等待状态3,表示请求输出井满,请求输出的用户进程等待;4为结束态,进程执行完成。
int count; //要临时输出的文件数
int x; //进程输出时的临时变量
}PCB[3];
struct reqblock //请求输出块
{
int reqname; //请求进程名
int length;//本次输出信息长度
int addr;//信息在输出井的首地址
}reqblock[10];
int buffer[2][100];//输出井
int c1[2] = { 100,100 };//分别表示两个用户进程可使用的输出井的空间
int buf0 = 0, buf1 = 0;//buf0代表buffer[0]的第一个可用空缓冲指针,buf1代表buffer[1]的第一个可用空缓冲指针。
int Ptr1 = 0, Ptr2 = 0;//Ptr1表示输出的第一个请求块指针,Ptr2是空闲请求输出块指针
int c3 = 10;//当前系统剩余的请求输出信息块个数
int t1 = 0, t2 = 0;//两个用户进程目前已经输出的文件数
int t3 = 0, t4 = 0;//两个用户进程目前已经存入输出井的文件数
void init();//初始化函数
void work();//模拟进程调度
void request(int);//用户进程运行函数
void spooling();//spooling进程运行函数
void work()//模拟进程调度
{
int i;
bool isFinish;
srand((unsigned)time(NULL));
while (true)
{
i = rand() % 100;
//cout << i << endl;
if (i <= 45 && PCB[0].status == 0)
{
if (t3 < PCB[0].count)
request(0);
}
else if (i > 45 && i <= 90 && PCB[1].status == 0)
{
if (t4 < PCB[1].count)
request(1);
}
else if (i > 90 && PCB[2].status == 0)
spooling();
//所有进程都结束了吗
isFinish = true;
for (int m = 0; m < 3; m++)
{
if (PCB[m].status != 4)
{
isFinish = false;
break;
}
}
if (isFinish) //若所有进程都结束,则退出
{
cout << "所有进程都结束了!" << endl;
return;
}
}
}
void init()//初始化函数
{
int i, j;
cout << "请输入两个用户进程请求输出的文件个数:" << endl;
for (i = 0;i < 2;i++)
cin >> PCB[i].count;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 100; j++)
buffer[i][j] = 0;
}
for (i = 0; i < 10; i++)
{
reqblock[i].length = 0;
reqblock[i].addr = 0;
}
for (i = 0; i < 3; i++)
{
PCB[i].id = i;
PCB[i].status = 0;
}
}
void request(int i)
{
if (c3 == 0) //判断是否有空闲的请求块
{
PCB[i].status = 3; //没有空闲的请求块,进程状态置3
cout << "没有空闲的请求块,进程状态置3" << endl;
return;
}
c3--;//申请一个空闲的请求输出块
int file_length = 0;
int address0 = buf0;
int address1 = buf1;
if (i == 0)
{
cout << "+++++++++++++调用进程0+++++++++++++" << endl;
while (true)
{
PCB[0].x = rand() % 10;
if (PCB[0].x != 0)
{
if (c1[0] == 0)//判断输出井是否有空间
{
PCB[0].status = 1;
cout << "输出井满,进程状态置1" << endl;
return;
}
buffer[0][buf0] = PCB[0].x;
//cout << PCB[0].x << " ";
c1[0]--;
buf0 = (buf0 + 1) % 100;
file_length++;
}
else if(PCB[0].x == 0)
{
reqblock[Ptr2].length = file_length;
reqblock[Ptr2].reqname = 0;
reqblock[Ptr2].addr = address0;
Ptr2 = (Ptr2 + 1) % 10;
t3++;
if (PCB[2].status == 2)
PCB[2].status = 0;
return;
}
}
}
else if (i == 1)
{
cout << "+++++++++++++调用进程1+++++++++++++" << endl;
while (true)
{
PCB[1].x = rand() % 10;
if (PCB[1].x != 0)
{
if (c1[1] == 0)//判断输出井是否有空间
{
PCB[1].status = 1;
cout << "输出井满,进程状态置1" << endl;
return;
}
buffer[1][buf1] = PCB[1].x;
//cout << PCB[1].x << " ";
c1[1]--;
buf1 = (buf1 + 1) % 100;
file_length++;
}
else if (PCB[1].x == 0)
{
reqblock[Ptr2].length = file_length;
reqblock[Ptr2].reqname = 1;
reqblock[Ptr2].addr = address1;
Ptr2 = (Ptr2 + 1) % 10;
t4++;
if (PCB[2].status == 2)
PCB[2].status = 0;
return;
}
}
}
}
void spooling()
{
cout << "+++++++++++++调用spooling进程+++++++++++++" << endl;
if (c3 == 10)
{//如果没有请求块
if (PCB[0].status == 4 && PCB[1].status == 4)
{//是否所有输出进程结束
PCB[2].status = 4;
return;
}
else
{
PCB[2].status = 2;
return;
}
}
cout << "*******************************************************************************" << endl;
//按照请求块从输出井中取数据输出(打印到屏幕)
//遍历请求块
while (c3 < 10)
{
int reqname = reqblock[Ptr1].reqname;
int addr = reqblock[Ptr1].addr;
int length = reqblock[Ptr1].length;
cout << "SPOOLING输出进程为:" << reqname << endl;
cout << "调用SPOOLING进程,释放的进程块序号为ReqBlock[" << Ptr1 << "]" << endl;
cout << "以下为输出结果:" << endl;
int k;
if (reqname == 0)
{
for (k = 0; k < length; k++)
cout << buffer[0][(addr + k) % 100] << " ";
cout << endl;
c1[0] = c1[0] + length;
t1++;
if (t1 == PCB[0].count) {
PCB[0].status = 4;
}
}
else if (reqname == 1)
{
for (k = 0; k < length; k++)
cout << buffer[1][(addr + k) % 100] << " ";
cout << endl;
c1[1] = c1[1] + length;
t2++;
if (t2 == PCB[1].count) {
PCB[1].status = 4;
}
}
cout << endl;
c3++;
Ptr1 = (Ptr1 + 1) % 10;
}
if (PCB[0].status == 3) //修改阻塞进程状态为就绪
PCB[0].status = 0;
if (PCB[1].status == 3)
PCB[1].status = 0;
cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl << endl;
return;
}
int main() //主程序
{
srand((unsigned)time(NULL));
init();
cout << "\n>>>>>>>>>>>>>>>> SPOOLing系统模拟程序 <<<<<<<<<<<<<<<<<\n";
cout << "进程0创建" << PCB[0].count << "个文件" << endl;
cout << "进程1创建" << PCB[1].count << "个文件" << endl;
work();
return 0;
}