设计模拟一个SPOOLING假脱机输出程序

(1) 课程设计题目及内容

设计模拟一个SPOOLING假脱机输出程序
设计一个SPOOLING输出进程和两个请求输出的用户进程,以及一个SPOOLING输出服务程序request。当用户进程希望输出一系列信息时,调用SPOOLING输出服务程序request,由输出服务程序将该信息送入输出井。待给出一个结束标志时,表示进程该次的文件输出结束。之后,申请一个输出请求块,用来记录请求输出的用户进程的名字、要输出的文件名以及要输出信息的长度等。等待SPOOLING输出进程进行输出。这里,SPOOLING输出进程与请求输出的用户进程可并发运行。SPOOLING输出进程工作时,根据请求块记录的各进程要输出的信息,将其实际输出到打印机或显示器,这里记录到一个文件中。

(2) 程序中使用的数据结构及主要符号说明

进程标识用结构体pcb表示,整型id表示进程标识数,status表示进程状态。
struct pcb
{
int id; // 进程标识数
int status; // 进程状态
};

文件标识用结构体filehandle表示,整型file_length表文件长度,在开始进程前随机写入,file_already表已写入输出井中的长度。
struct filehandle //文件标识
{
int file_length;//文件长度
int file_already;//文件已写入缓冲的长度
};

申明一个全局二维指针,用于申请动态二维数组时表示两个进程的文件
extern filehandle FH;

status = 0 为可执行态;
status = 1 为等待状态1,表示请求输出块用完,请求输出的用户进程等待;
status = 2 为等待状态2, 表示输出井空,SPOOLING输出进程等待;
status = 3 为结束态,进程执行完成。

请求块用结构体block表示,整型reqname记录请求块对应的进程名,sta对应该请求块在输出井中开始输出的起点,length表示该请求块对应的写入数据总长度。

struct block
{
int reqname; // 请求进程名
int sta; //请求块对应输出井中起点
int length; // 本次输出信息长度
};
extern pcb PCB[3];
extern block reqblock[block_num];
extern int T[2];//进程1、2需要完成输出的文件数目
extern int t[2];//进程1、2已经完成输出的文件数目

extern int n_in, n_out;//送取数据时的块数标记,取值为0~9(超过9时模10),因为有C3作标记,无需考虑循环队列的判空判满,只要考虑各自位置即可
整型C3标记请求块剩余数目,同时循环队列判空判满
extern int C3;//请求块剩余块数

为每个进程开辟一个文件共享区
extern int buffer[2][buffer_size];//输出井
extern int bufferleft[2];//输出井剩余空间

(3) 程序流程图和带有注释的源程序

程序流程图

设计模拟一个SPOOLING假脱机输出程序_第1张图片
设计模拟一个SPOOLING假脱机输出程序_第2张图片
设计模拟一个SPOOLING假脱机输出程序_第3张图片

Spooling.h

#include 
#include 

#define p1_fnum 5  //进程一需要输出的文件数目
#define p2_fnum 2  //进程二需要输出的文件数目
#define f_maxsize 10  //一个文件所占输出井最大空间
#define buffer_size 30  //一块输出井大小
#define block_num 10  //请求块数目

struct pcb
{
	int id;      // 进程标识数 
	int status;    // 进程状态 
};

struct filehandle   //文件标识
{
	int file_length;//文件长度
	int file_already;//文件已写入缓冲的长度
};

extern filehandle** FH;
/*
status = 0 为可执行态;
status = 1 为等待状态1,表示请求输出块用完,请求输出的用户进程等待;
status = 2 为等待状态2, 表示输出井空,SPOOLING输出进程等待;
status = 3 为结束态,进程执行完成。
*/
struct block
{
	int reqname;          // 请求进程名 
	int sta;              //请求块对应输出井中起点
	int length;           // 本次输出信息长度 
};

extern pcb PCB[3];
extern block reqblock[block_num];

extern int T[2];//进程1、2需要完成输出的文件数目
extern int t[2];//进程1、2已经完成输出的文件数目
extern int n_in, n_out;//送取数据时的块数标记,取值为0~9(超过9时模10),因为有C3作标记,无需考虑循环队列判空判满,只要考虑各自位置即可
extern int C3;//请求块剩余块数
extern int buffer[2][buffer_size];//输出井
extern int bufferleft[2];//输出井剩余空间

void systemInitialize();//进程、输出井初始化

int getpid();  //获取随机调度的进程
void printblock(int num);//在spooling中打印对应块的内容
int getfinish();//查询完成资源数
void renewprocess();//更新子进程状态

void spooling();//spooling调度算法
void request(int pid);//输出进程请求

Spooling.cpp

#include"SPOOLING.h"

pcb PCB[3];
block reqblock[10];
filehandle** FH = (filehandle**)(malloc(sizeof(filehandle*) * 2));
int T[2] = { p1_fnum, p2_fnum };//进程1、2需要完成输出的文件数目
int t[2] = { 0,0 };//进程1、2已经完成输出的文件数目
int n_in = 0, n_out = 0;//送取数据时的块数标记,取值为0~9(超过9时模10),因为有C3作标记,无需考虑循环队列判空判满,只要考虑各自位置即可
int C3 = block_num;//请求块剩余块数
int buffer[2][buffer_size];//输出井
int bufferleft[2] = { buffer_size,buffer_size };//输出井剩余空间

void systemInitialize()
{
	FH[0] = (filehandle*)malloc(sizeof(filehandle) * p1_fnum);
	FH[1] = (filehandle*)malloc(sizeof(filehandle) * p2_fnum);
	std::cout << "进程1共有" << p1_fnum << "个文件" << std::endl;
	for (int i = 0; i < p1_fnum; i++)
	{
		FH[0][i].file_already = 0;
		FH[0][i].file_length = rand() % 20 + 1;
		std::cout << "文件" << i + 1 << "长度为" << FH[0][i].file_length << std::endl;
	}
	std::cout << "进程2共有" << p2_fnum << "个文件" << std::endl;
	for (int i = 0; i < p2_fnum; i++)
	{
		FH[1][i].file_already = 0;
		FH[1][i].file_length = rand() % 20 + 1;
		std::cout << "文件" << i + 1 << "长度为" << FH[1][i].file_length << std::endl;
	}
	std::cout << std::endl;
	for (int i = 0; i < 3; i++)
	{
		PCB[i].id = i;
		PCB[i].status = 0;//初始均为可执行态
	}
}

int getpid()
{
	int p = rand() % 100 + 1;
	if (p <= 20)
	{
		return 0;
	}
	else if (p > 20 && p <= 60)
	{
		return 1;
	}
	else
	{
		return 2;
	}
}

int getfinish()
{
	int finish = 0;
	for (int i = 0; i < 3; i++)
	{
		if (PCB[i].status == 3)
		{
			finish++;
		}
	}
	return finish;
}

void printblock(int num)
{
	std::cout << "打印请求块" << num + 1 << "的内容,对应的进程为进程" << reqblock[num].reqname << "  ";
	for (int i = 0; i < reqblock[num].length; i++)
	{
		std::cout << buffer[(reqblock[num].reqname - 1)][reqblock[num].sta + i] << " ";
	}
	std::cout << std::endl;
}

void spooling()
{
	if (C3 == block_num)
	{
		if (getfinish() == 2)//其它进程已结束,SPOOLING进程结束
		{
			std::cout << "没有正在运行中的子进程,spooling结束" << std::endl;
			PCB[0].status = 3;
			return;
		}
		else//其它进程未结束,输出井为空,SPOOLING等待
		{
			std::cout << "输出井中内容为空,spooling挂起" << std::endl;
			PCB[0].status = 2;
			return;
		}
	}
	else//打印输出井的内容
	{
		PCB[0].status = 0;
		for (; n_out != n_in; n_out = (n_out + 1) % 10)
		{
			printblock(n_out);
			C3++;//所剩块加一
		}
		bufferleft[0] = buffer_size;
		bufferleft[1] = buffer_size;
		if (PCB[1].status == 1)
		{
			std::cout << "进程1等待中,唤醒进程1" << std::endl;
			request(1);
		}
		if (PCB[2].status == 1)
		{
			std::cout << "进程2等待中,唤醒进程2" << std::endl;
			request(2);
		}
		return;
	}
}

void request(int pid)
{
	if (C3 == 0)//请求块剩余数为0或对应的输出井区域所剩空间不足
	{
		std::cout << "请求块或输出井剩余资源不足,进程进入等待状态" << std::endl;
		PCB[pid].status = 1;//等待状态1,表示请求所需要的资源不足,请求输出的用户进程等待
		return;//返回调度程序
	}
	else
	{
		reqblock[n_in].reqname = pid;//请求块写入该进程pid
		reqblock[n_in].sta = buffer_size - bufferleft[pid-1];
		int pen; int l = 0;
		std::cout <<"进程"<<pid<<"的文件"<< t[pid-1]+1 <<"往输出井写入: ";
		for (int i = 0; i < bufferleft[pid - 1] && FH[pid - 1][t[pid - 1]].file_already < FH[pid - 1][t[pid - 1]].file_length && i < f_maxsize; i++)//若当前输出井还有空间 且 文件未结束 且 本文件本次输出尚未超过20个字符
		{
			//写文件,如果已经是最后一个字符了,写完break,表明文件写完
			if (FH[pid - 1][t[pid - 1]].file_already == FH[pid - 1][t[pid - 1]].file_length - 1)
			{
				pen = 0;
			}
			else
			{
				pen = rand() % 9 + 1;
			}
			buffer[pid - 1][buffer_size - bufferleft[pid - 1] + l] = pen;//写入输出井
			FH[pid - 1][t[pid - 1]].file_already++;
			//每次写字符,该文件已写字符数往后走一步
			l++;
			std::cout << "  " << pen;
		}
		std::cout << std::endl;
		if (buffer[pid - 1][buffer_size - bufferleft[pid - 1] + l - 1] == 0)//读取到文件结束符
		{
			t[pid - 1]++;//该进程完成文件数加一
		}
		else//表明文件未输出完毕,挂起
		{
			PCB[pid].status = 1;
		}
		bufferleft[pid-1] -= l;
		reqblock[n_in].length = l;//文件输出流长度写入该块
		C3--;//所剩请求块减一
		n_in = (n_in + 1) % block_num;   //写入块往下走
		if (PCB[0].status == 2)
		{
			std::cout << "SPOOLING等待中,唤醒SPOOLING" << std::endl;
			spooling();//唤醒SPOOLING
		}
	}
}

void renewprocess()//更新进程完成状态
{
	if (T[0] == t[0])
	{
		PCB[1].status = 3;
	}
	if (T[1] == t[1])
	{
		PCB[2].status = 3;
	}
}

(4) 执行程序名,并打印程序运行时的初值和运算结果

设计模拟一个SPOOLING假脱机输出程序_第4张图片
设计模拟一个SPOOLING假脱机输出程序_第5张图片

你可能感兴趣的:(数据结构)