操作系统课设——设计模拟一个SPOOLING假脱机输出程序

广州大学操作系统课程设计报告

要求:书写课程设计报告,报告中应该包含如下内容:
一.课程设计题目及内容
课程设计题目:题目三: 设计模拟一个SPOOLING假脱机输出程序
(1) 系统设计要求:设计一个SPOOLING输出进程和两个请求输出的用户进程,以及一个SPOOLING输出服务程序request。当用户进程希望输出一系列信息时,调用SPOOLING输出服务程序request,由输出服务程序将该信息送入输出井。待给出一个结束标志时,表示进程该次的文件输出结束。之后,申请一个输出请求块,用来记录请求输出的用户进程的名字、要输出的文件名以及要输出信息的长度等。等待SPOOLING输出进程进行输出。这里,SPOOLING输出进程与请求输出的用户进程可并发运行。SPOOLING输出进程工作时,根据请求块记录的各进程要输出的信息,将其实际输出到打印机或显示器,这里记录到一个文件中。
(2) 进程调度:采用随机调度算法,这与进程要求输出信息的随机性相一致。两个请求输出的用户进程的调度概率各为40%,SPOOLING输出进程被调度的概率为20%,这由随机数发生器产生的随机数来模拟决定。
(3) 进程状态:进程有三个基本状态,分别为可执行、等待和结束。状态变化的条件为:
1) 当进程正在运行或等待调度时的状态为可执行态。
2) 服务程序在将用户输出信息送输出井时,如发生输出请求块已用完,将调用它的用户进程置为“等待状态1”。
3) SPOOLING输出进程在进行输出时,若发现输出请求块为空,则进入“等待状态2”。
4) SPOOLING输出进程输出一个信息块后,应将正在等待输出的进程置为“可执行状态”。
5) 服务程序在输出信息到输出井并形成输出请求信息块后,若SPOOLING进程处于等待态,则将其置为“可执行状态”。
6) 进程执行完成时,置为“结束态”。

二.程序中使用的数据结构及主要符号说明
(4) 数据结构:
1) 进程控制块(PCB)如下:

struct pcb //进程控制块PCB
{int id;		//进程标识 int status;	//状态0为可执行态;等待状态1,表示请求输出块用完,请求输出的用户进程等待;等待状态2,表示输出井空,SPOOLING输出进程等待;3为结束态int length;//输出长度 
}PCB[PROCESSNUM + 1];     
其中:status=0 为可执行态;status=1 为等待状态1,表示请求输出块用完,请求输出的用户进程等待;status=2 为等待状态2, 表示输出井空,SPOOLING输出进程等待;status=3 为结束态,进程执行完成。

2) 请求输出块reqblock 如下:

struct reqblock   //请求输出块
{int reqid;//要求输出的进程 int tname;int length;//输出长度 int addr;//输出首地址 
}ReqBlock[REQBLOCKNUM];

3) 输出井BUFFER。SPOOLING系统为每个请求输出的进程在输出井中分别开辟一个区。本题目可设计一个二维数组(int buffer[T1][30] 和 buffer[T2][30])作为输出井。每个进程一个文件最多可占用输出井20个位置。

struct BUFFER  //输出井结构
{int buf[OUTBUFFERNUM];   //输出井缓冲区int usedNum;     //输出井缓冲区已使用的数目int head;  //指示输出井空闲块首地址//int tail;  //指示输出井信息块(有信息的部分)尾地址
}OutBuffer[PROCESSNUM];

三.程序流程图和带有注释的源程序

SPOOLING系统输出模拟的主控流程图如图3-1所示:
SPOOLING输出服务程序request(由请求输出的两个用户进程调用)流程图如图3-2所示:
SPOOLING输出进程流程图如图3-3所示:
在这里插入图片描述
图3-1 SPOOLING系统输出模拟的主控流程图

在这里插入图片描述

图3-2 SPOOLING输出服务程序request流程图
在这里插入图片描述
图3-3 SPOOLING输出进程流程图

源程序:

#include "stdio.h"
#include "stdlib.h"
#include "time.h"
#include <iostream>
using namespace std;#define PROCESSNUM 2   //输出进程个数
#define OUTBUFFERNUM  30  //输出井存储字节个数
#define REQBLOCKNUM   10
#define T1   3          //定义用户进程0要输出的文件数T1
#define T2   3          //定义用户进程1要输出的文件数T2struct pcb //进程控制块PCB
{int id;		//进程标识 int status;	//状态0为可执行态;等待状态1,表示请求输出块用完,请求输出的用户进程等待;等待状态2,表示输出井空,SPOOLING输出进程等待;3为结束态int length;//输出长度 
}PCB[PROCESSNUM + 1];struct reqblock   //请求输出块
{int reqid;//要求输出的进程 int tname;int length;//输出长度 int addr;//输出首地址 
}ReqBlock[REQBLOCKNUM];struct BUFFER  //输出井结构
{int buf[OUTBUFFERNUM];   //输出井缓冲区int usedNum;     //输出井缓冲区已使用的数目int head;  //指示输出井空闲块首地址//int tail;  //指示输出井信息块(有信息的部分)尾地址
}OutBuffer[PROCESSNUM];int C3 = 10;              //C3表示当前系统剩余的请求输出信息块个数,初值为10
int n_out = 0, n_in = 0;  //指示当前使用的输出请求块,request从n_in开始取,spooling从n_out开始取int t1 = 0;       //设两个计时器,分别记录两个用户进程已经输出的文件个数,都初始化为0
int t2 = 0;
int t_num[2][10];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;}//自动生成用户进程0和用户进程1的文件长度/*for (i = 0; i < T1; i++){t_num[0][i] = (rand() % 30) + 1;}*//*for (i = 0; i < T2; i++){t_num[1][i] = (rand() % 30) + 1;}*///手动生成用户进程0和用户进程1的文件长度t_num[0][0] = 15;t_num[0][1] = 18;t_num[0][2] = 8;t_num[1][0] = 25;t_num[1][1] = 18;t_num[1][2] = 6;
}void request(int i)
{cout << "==============================================================================="<<endl;cout << "进程: " << i << " 调用request进程,写入的进程块序号为ReqBlock[" << n_in << "]" << endl;int j, length = 0;if (C3 == 0)    //判断是否有空闲的请求块{PCB[i].status = 1;  //没有空闲的请求块,进程状态置3cout << "没有空闲的请求块,进程状态置1" << endl;return;}C3--;//申请一个空闲的请求输出块//判断输出文件的字符数是否大于20,如果大于20,标志aa和bb会置为falsebool aa = true;bool bb = true;if (i == 0) //如果是用户进程0for (int k = 0; k < t_num[0][t1]; k++) {j = (rand() % 10) + 1;//随机数if (k == 20) {aa = false;cout << endl<<"该文件个数大于20,将被挂起" << endl;t_num[0][t1] = t_num[0][t1] - 20;PCB[0].status = 1;break;}OutBuffer[0].buf[(OutBuffer[i].head + k) % OUTBUFFERNUM] = j; //J送buffer[0][length]cout << j << " ";OutBuffer[0].usedNum++;//判断输出井是否满if (OutBuffer[0].usedNum == OUTBUFFERNUM) {cout << endl<<"输出井满" << endl;ReqBlock[n_in].length = k+1;t_num[0][t1] = t_num[0][t1] - ReqBlock[n_in].length;ReqBlock[n_in].reqid = i;ReqBlock[n_in].addr = OutBuffer[i].head;n_in = (n_in + 1) % REQBLOCKNUM; //修改的输出请求块的个数加1PCB[0].status = 1;   //挂起进程return;}}else {  //如果是用户进程1for (int k = 0; k < t_num[1][t2]; k++) {j = (rand() % 10) + 1;//随机数if (k == 20) {bb = false;cout << endl<<"该文件个数大于20,将被挂起" << endl;t_num[1][t2] = t_num[1][t2] - 20;PCB[1].status = 1;break;}OutBuffer[1].buf[(OutBuffer[i].head + k) % OUTBUFFERNUM] = j; //J送buffer[0][length]cout << j << " ";OutBuffer[1].usedNum++;//判断输出井是否满if (OutBuffer[1].usedNum == OUTBUFFERNUM) {cout << "输出井满" << endl;PCB[1].status = 1;         //挂起进程ReqBlock[n_in].length = k+1;t_num[1][t2] = t_num[1][t2] - ReqBlock[n_in].length;ReqBlock[n_in].reqid = i;ReqBlock[n_in].addr = OutBuffer[i].head;n_in = (n_in + 1) % REQBLOCKNUM; //修改的输出请求块的个数加1return;}}}cout << endl;if (i == 0) {cout << "进程  " << i << "  文件的" << t1 << "的字符个数:" << t_num[0][t1] << endl << endl;if (aa) {ReqBlock[n_in].length = t_num[0][t1];cout << "                 <<<<<<<<<<<<<<<<<<<<<<进程结束>>>>>>>>>>>>>>>>>>>>" << endl << endl;t1++;             //t1记录用户进程1已经输出的文件个数}elseReqBlock[n_in].length = 20;}else {cout << "进程  " << i << "  文件" << t2 << "的字符个数:" << t_num[1][t2] << endl << endl;if (bb) {ReqBlock[n_in].length = t_num[1][t2];cout << "                 <<<<<<<<<<<<<<<<<<<<<<进程结束>>>>>>>>>>>>>>>>>>>>" << endl << endl;t2++;             //t2记录用户进程1已经输出的文件个数}elseReqBlock[n_in].length = 20;}//填写请求块ReqBlock[n_in].reqid = i;  //置该输出请求块的进程名字为iReqBlock[n_in].addr= OutBuffer[i].head;       //修改输出首地址OutBuffer[i].head = (OutBuffer[i].head + ReqBlock[n_in].length) % OUTBUFFERNUM;if (PCB[PROCESSNUM].status == 2)  //若spooling进程阻塞,则修改其状态为可执行(0)PCB[PROCESSNUM].status = 0;n_in = (n_in + 1) % REQBLOCKNUM; //修改的输出请求块的个数加1}void spooling()
{//请完成spooling函数的设计if (C3 == 10) {//如果没有请求块if (PCB[0].status == 3 && PCB[1].status == 3) {//是否所有输出进程结束PCB[2].status = 3;return;}else {PCB[2].status = 2;return;}}cout << "*******************************************************************************" << endl;//按照请求块从输出井中取数据输出(打印到屏幕)//遍历请求块while (C3 < 10) {int requid = ReqBlock[n_out].reqid;int addr = ReqBlock[n_out].addr;int length = ReqBlock[n_out].length;cout << "addr" << addr << endl;cout << "SPOOLING输出进程为:" << requid << endl;cout << "调用SPOOLING进程,释放的进程块序号为ReqBlock[" << n_out << "]" << endl;cout << "以下为输出结果:" << endl;int k;if (requid == 0) {for (k = 0; k < length; k++)cout << OutBuffer[0].buf[(addr + k) % OUTBUFFERNUM] << " ";OutBuffer[0].usedNum = OutBuffer[0].usedNum - length;}else {for (k = 0; k < length; k++)cout << OutBuffer[1].buf[(addr + k) % OUTBUFFERNUM] << " ";OutBuffer[1].usedNum = OutBuffer[1].usedNum - length;}cout << endl;C3++;//将数据从输出井输出n_out = (n_out + 1) % REQBLOCKNUM;}if (PCB[0].status == 1)  //修改阻塞进程状态为就绪PCB[0].status = 0;if (PCB[1].status == 1)PCB[1].status = 0;cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl<<endl;return;}void work()//模拟进程调度 
{int i;bool isFinish;srand((unsigned)time(NULL));while (1){i = rand() % 100;if (i <= 40 && PCB[0].status == 0){if (t1 < 3) {request(0);}}else if (i <= 80 && PCB[1].status == 0){if (t2 < 3) {request(1);}}else if (i > 80 && PCB[2].status == 0){spooling();}//所有进程都结束了吗isFinish = true;if (t1 == T1) {PCB[0].status = 3;}if (t2 == T2) {PCB[1].status = 3;}for (i = 0; i < PROCESSNUM + 1; i++) {if (PCB[i].status != 3)isFinish = false;}if (isFinish)     //若所有进程都结束,则退出return;}}
int main() //主程序
{srand((unsigned)time(NULL));init();cout << "\n>>>>>>>>>>>>>>>> SPOOLing系统模拟程序 <<<<<<<<<<<<<<<<<\n";cout << "进程0创建" << T1 << "个文件" << endl;for (int i = 0; i < T1; i++) {cout << "进程0文件" << i << "的文件个数是" << t_num[0][i] << endl;}cout << endl;cout << "进程1创建" << T2 << "个文件" << endl;for (int i = 0; i < T2; i++) {cout << "进程1文件" << i << "的文件个数是" << t_num[1][i] << endl;}cout << endl;work();return 0;}

四.执行程序名,并打印程序运行时的初值和运算结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
五.实验结果分析,实验收获和体会
在这里插入图片描述
在这里插入图片描述
操作系统是比较复杂,抽象的课程。单单看书,很难领会操作系统的知识。只有多动手,多做实验,才会对操作系统的知识有更深刻的体会,比如文件管理,SPOOLING技术等。纸上得来终觉浅,绝知此事要躬行。
六.实验的改进意见和建议。
1.我觉得操作系统课程设计放在期末考试前是一种不妥的行为,一方面学生要忙于复习,另一方面又要忙于课程设计。既影响复习也影响课设完成的质量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/418839.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

操作系统实验——进程管理与进程通信

广州大学学生实验报告 实验一 进程管理与进程通信 一、实验目的 1、掌握进程的概念&#xff0c;明确进程的含义。 2、认识并了解进程并发执行的实质&#xff0c;进程的阻塞与唤醒&#xff0c;终止与退出的过程。 3、熟悉进程的睡眠、同步、撤消等进程控制方法。 4、分析进程…

前端学习(1815):前端调试之css flex 练习1

index.html <!DOCTYPE html> <html lang"en"><head><!--系统内置 start--><script type"text/javascript"></script><!--系统内置 end--><meta charset"UTF-8" /><meta name"viewport…

关于操作系统的学习总结

学了一学期的操作系统&#xff0c;就瞎写点东西反思一下吧。 我是广州大学计算机科学与技术专业的&#xff0c;操作系统的知识是比较抽象的。第一看书时必要的。我们的操作系统课程是张艳玲副教授授课的。张老师讲课认真&#xff0c;是一个不错的老师。我们上课用的课本是这本…

iis6 配置python CGI

打开iis管理器&#xff0c;在Web服务扩展中添加一个新的Web服务扩展 点击添加&#xff0c;浏览找到python的目录&#xff0c;文件类型改为CGI exe文件 选择python.exe 然后在目录后添加 %s %s&#xff08;搜了一圈&#xff0c;还没找到原因&#xff09; 确定就行&#xff0c;然…

广州大学专业选修课介绍-----------Linux操作系统分析及实践

教材&#xff1a; 课程内容&#xff1a;你去看一下课本就知道教什么了(●◡●) 考核方式&#xff1a;考察

今天课堂总结

1.带缓存的字符输入输出流 1 package com.xia;2 3 import java.io.BufferedReader;4 import java.io.BufferedWriter;5 import java.io.File;6 import java.io.FileReader;7 import java.io.FileWriter;8 9 public class test { 10 11 public static void main(String[] a…

微信服务项目表

本文介绍了方倍工作室对外提供的微信相关服务介绍&#xff0c;供有需要购买的客户进行参考。 免费服务图书购买语音问答代码视频技术咨询企业顾问定制服务服务内容微信基础教程常用代码下载微信完整教程图书源码下载发起问题查看他人答案微信高级代码微信开发视频微信开发技术技…

前端学习(1818):前端面试题之封装函数之进行字符串驼峰的命名

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><script type"text/javascript">//已知有字符串fooget-element-by-id,写一个function将其转化成驼峰表示法”getE…

前端学习(1819):前端面试题之封装函数之冒泡排序

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><script type"text/javascript">var arr [32,4,67,82,21,11];///轮数for(var i 0; i<arr.length-1;i){//次数…

前端学习(1821):前端面试题之封装函数之去重

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><script type"text/javascript">/** 1.创建一个新数组,把原数组中的第一个元素插入到新数组中* 2.遍历原数组中的…

天猫整站SSM-分页-limit(做个人学习笔记整理用)

数据库使用的是mysql 要想在Mybatis中使用分页查询&#xff0c;首先要清楚mysql中limit的用法。 limit a,b a是从第a1条数据开始&#xff0c;b是指读取几条数据 例如&#xff1a;select * from table limit 0,10 这句sql语句是说从表中获取第1条开始的10条记录

天猫整站SSM-分页-herf(做个人学习笔记整理用)

天猫整站SSM-分页-&#xff08;做个人学习笔记整理用&#xff09;<li ><a href"?start${page.start-page.count}" aria-label"Previous" ><span aria-hidden"true">‹</span></a> </li>如&#xff1a;<…

Lab1--关于安装JUnit的简要描述

安装JUnit的过程描述&#xff1a; 下载两个jar包&#xff1a; hamcrest-all-1.3.jar junit-4.12.jar 注意在导入完成jar包之后不要随意改变jar包的路径。 创建java程序&#xff0c;书写如下代码进行测试&#xff1a; triangle.java package triangle; public class triangle { …

天猫整站SSM-后台分类管理-增加(做个人学习笔记整理用)

天猫整站SSM-后台分类管理-增加&#xff08;做个人学习笔记整理用&#xff09; CategoryController&#xff1a; request.getSession().getServletContext()// 获取的是page的上下文。 request.getSession().getServletContext().getRealPath(“”); 是获取的的tamcat的路径&a…

Delphi iOS 开启文件共享 UIFileSharingEnabled

Apple 在 iOS 提供了文件共享&#xff08;FileSharing&#xff09;功能&#xff0c;让 App 有一个对外窗口的目录&#xff0c;透过 iTunes 可以任意管理这个目录的文档内容&#xff08;可拖入文档&#xff0c;也能将文档拖出备份&#xff09;。 如果 App 需要文件共享&#xff…

iOS:iOS开发系列–打造自己的“美图秀秀”(中)

来源&#xff1a; KenshinCui 链接&#xff1a;http://www.cnblogs.com/kenshincui/p/3959951.html 其他状态设置 常用的图形上下文状态设置上面基本都用到了&#xff0c;我们不再一一解释&#xff0c;这里着重说一下叠加模式和填充模式&#xff0c;初学者对于这两个状态设置…