SP00LING假脱机输入输出技术模拟

题目 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;
}

觉得有用的话就点个赞吧,蟹蟹!!!

  • 11
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
SPOOLING技术 一、实验目的 理解和掌握SPOOLING技术。 二、实验内容 编写程序实现SPOOLING技术模拟。 三、实验要求 1、设计一个实现SPOOLING技术的进程 设计一个SPOOLING输出进程和两个请求输出的用户进程及一个SPOOLING输出服务程序。 SPOOLING输出进程工作时,根据请求块记录的各进程要输出的信息,将其实际输出到打印机或显示器。这里,SPOOLING进程与请求输出的用户进程可并发运行。 2、设计进程调度算法 进程调度采用随机算法,这与进程输出信息的随机性相一致。两个请求输出的用户进程的调度概率各为45%,SPOOLING输出进程为10%,这由随机数发生器产生的随机数模拟决定。 3、进程状态 进程基本状态有3种,分别为可执行、等待和结束。可执行状态就是进程正在运行或等待调度的状态;等待状态又分为等待状态1、等待状态2、等待状态3。 状态变化的条件为: (1)进程执行完成时,置为“结束”状态。 (2)服务程序在将输出信息送至输出井时,如发现输出井已满,将调用进程置为“等待状态1”。 (3)SPOOLING进程在进行输出时,若输出井空,则进入“等待状态2”。 (4)SPOOLING进程输出一个信息块后,应立即释放该信息块所占的输出井空间,并将正在等待输出的进程置为“可执行状态”。 (5)服务程序在输出信息到输出井并形成输出请求信息块后,若SPOOLING进程处于等待状态则将其置为“可执行状态”。 (6)当用户进程申请请求输出块时,若没有可用请求块时,调用进程进入“等待状态3”。 4、数据结构 1)进程控制块PCB struct pcb { int status; int length; }pcb[3]; 其中status表示进程状态,其取值: 0 表示可执行状态; 1 表示等待状态1; 2 表示等待状态2; 3 表示等待状态3 2)请求输出块reqblock struct{ int reqname;//请求进程名 int length;// 本次输出信息长度 int addr;// 信息在输出井的首地址 }reqblock[10]; 3)输出井BUFFER SPOOLING系统为每个请求输出的进程在输出井中分别开辟一个区。本实验可设计一个二维数组(int buffer[2][10])作为输出井。每个进程在输出井最多可占用10个位置。 5、编程说明 为两个请求输出的用户进程设计两个输出井。每个可存放10个信息,即buffer[2][10]。当用户进程将其所有文件输出完时,终止运行。 为简单起见,用户进程简单的设计成:每运行一次,随机输出数字0~9之间的一个数,当输入10个数时形成一个请求信息块,填入请求输出信息块reqblock结构中。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值