操作系统课程实验代码汇总

本次内容供需要有相关实验需要的提供参考,代码下载方式在文末

文章目录

  • 操作系统课程实验代码汇总
  • 前言
  • 一、进程管理
    • 实验目的
    • 代码
    • 说明
  • 二、进程调度
    • 实验目的
    • 说明
  • 三、银行家算法
    • 实验目的
    • 代码
    • 说明
  • 四、虚拟存储器管理
    • 实验目的
    • 代码
    • 说明
  • 五、设备管理
    • 实验目的
    • 代码
    • 说明
  • 实验六 spooling技术
    • 实验目的
    • 代码
    • 说明

前言

本次更新的是操作系统课程实验的代码和实验内容


提示:以下是本篇文章正文内容,下面案例可供参考:主要涉及的实验有:1.进程管理、2.进程调度、3.银行家算法、4.虚拟存储器管理、5.设备管理、6、spooling技术

一、进程管理

实验目的

  1. 理解进程概念,明确进程和程序的区别。
  2. 理解并发执行的实质。
  3. 掌握进程的创建和撤销等进程控制方法。

代码

主函数

#include "ProcessControl.h"void showLine(){printf("**************************\n");
}int main(int argc, const char * argv[]) {//运行(就绪)队列(头结点不储存信息)PCB *running_list = (PCB *)malloc(sizeof(PCB));running_list->next = NULL;//阻塞队列(头结点不储存信息)PCB *block_list = (PCB *)malloc(sizeof(PCB));block_list->next = NULL;//当前运行的进程数量int storage_number = 0;int choose = 1;while (choose) {//展示菜单showLine();printf("*     进程演示系统      *\n");showLine();printf("1.创建新的进程  2.查看运行进程\n");printf("3.换出某个进程  4.杀死运行进程\n");printf("5.唤醒某个进程  6.退出程序   \n");showLine();printf("请选择(1~6):\n");scanf("%d",&choose);switch (choose) {case 1://创建新的进程create(running_list, block_list, &storage_number);break;case 2://查看运行进程show_running(running_list);break;case 3://换出某个进程change(running_list, block_list, &storage_number);break;case 4://杀死运行进程killed(running_list, &storage_number);break;case 5://唤醒某个进程wake_up(running_list, block_list, &storage_number);break;case 6:return 0;default:printf("没有这个选项!\n");break;}}return 0;
}

另外还有两个文件就不展示出来,代码资源会上传供下载使用

说明

打开程序后,进入界面可以看到6各功能模块,可根据操作系统知识来完成相应操作
用C语言编写程序,模拟实现创建新的进程;查看运行进程;换出某个进程;杀死运行进程等功能。
程序运行后出现界面,提供“创建新的进程”、“查看运行进程”等6项功能供用户选择,用户通过在界面输入各个功能所对应的标号选择执行不同的功能。

二、进程调度

实验目的

  1. 理解有关进程控制块,进程队列的概念。
  2. 掌握进程优先权调度算法和时间片轮转调度算法的处理逻辑。
    代码如下:
#include<iostream.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
// using namespace std;#define JOBSUM    9    //进程/作业总数
#define JOBNUM    5    //允许的作业道数
#define PRITOP    3    //最高优先级级数#define TIMELIMIT 10    //时间限制struct Job{    //作业
char jname[40];    //作业名
int start;    //到达时间
int worktime;    //工作时间
Job *next; //链接指针
int   pri; };struct PCB{PCB* next;char pname[40];    //进程名
int time;    //进程运行时间 char status;    //运行状态
};bool CreateJob(Job* jobtable,char name[])    //创建作业,将作业放入作业调度表
{//随机生成一个作业Job *p = new Job;strcpy(p->jname,name);p->start = rand()%(TIMELIMIT-1)+1;
p->worktime = rand()%(TIMELIMIT-p->start)+1;
p->pri = rand()%PRITOP;
p->next = NULL;//将作业放入作业调度表Job* now = jobtable;//将作业放入作业调度表,按到达时间排序if(now->next==NULL){    //后备队列还是空的时候now->next = p;}else{if(p->start <= now->next->start){    //当新生成的作业工作时间比后备队列第一个作业工作时间就小p->next = now->next;now->next = p;}else{Job *q = now->next;while( (p->start > q->start) && (q->next!=NULL) ){    //找到插入的位置q = q->next;}if( (p->start > q->start) && q->next==NULL){    //新生成的作业的start比后备队列中所有作业的start都大,则排在最后q->next = p;}else if(p->start <= q->start){    //找到插入的位置,这个位置的start小于或者等于下一个节点的startJob *t = now->next;while(t->next!=q){t = t->next;}t->next = p;p->next = q;}}}return true;}bool AddHoubei(Job *jobtable,Job *p,Job *&jhead)    //将作业p放入后备队列jhead,按短作业优先放置{//将作业p从作业调度表jobtable中去除Job* q = jobtable;while(q->next!=p && q->next!=NULL){q = q->next;}if(q->next==p){q->next = p->next;p->next = NULL;}//将作业p放入后备队列jhead,按短作业优先放置if(jhead==NULL){    //后备队列还是空的时候jhead = p;}else{if(p->worktime <= jhead->worktime){    //当新生成的作业工作时间比后备队列第一个作业工作时间就小p->next = jhead;jhead = p;}else{Job *q = jhead;while( (p->worktime > q->worktime) && (q->next!=NULL) ){    //找到插入的位置q = q->next;}if( (p->worktime > q->worktime) && q->next==NULL){    //新生成的作业的worktime比后备队列中所有作业的worktime都大,则排在最后q->next = p;}else if(p->worktime <= q->worktime){    //找到插入的位置,这个位置的worktime小于或者等于下一个节点的worktimeJob *t = jhead;while(t->next!=q){t = t->next;}t->next = p;p->next = q;}}}return true;}bool CreateProcess(PCB* &head,PCB* &tail,Job* &jhead)    //创建新进程{PCB* p = new PCB;char JobID = jhead->jname[3];strcpy(p->pname,"Process");    //进程名 p->pname[7] = JobID;p->pname[8] = '\0';p->status = 'R';    //就绪状态p->time = jhead->worktime;        //进程工作时间if(tail==NULL){//就绪队列还是空的,则第一次赋值head = p;tail = head;tail->next = head;}else{//就绪队列不为空tail->next = p;tail = p;p->next = head;}return true;
}bool Work(PCB* now)    //当前进程执行{now->time--;return true;}bool DropPro(PCB* &head,PCB* &tail,PCB* &chead,PCB* &ctail)    //将队首进程,推出循环就绪队列{PCB* p = head;        //保存头节点head = head->next;    //头结点指向他的下一个节点tail->next = head;    //将就绪队列尾节点直接指向新的头节点p->next = NULL;        //将分离出来的原来的头节点的next设为空NULLif(ctail==NULL){//已完成进程队列还是空的,则第一次赋值chead = p;ctail = chead;}else{//已完成进程队列不为空,则将当前已完成进程放到队列尾部ctail->next = p;ctail = ctail->next;}return true;}bool NextPro(PCB* &head,PCB* &tail)    //当前进程已执行了一个时间片,将其置于循环队列尾端。即将head和tail向前推进一次{head = head->next;tail = tail->next;return true;}void printRQ(PCB* head,int readynum)    //打印当前就绪队列{PCB* p = head;printf("=> ");if(readynum==0){//就绪队列已空printf("空\n");return ;}while(p->next!=head){printf("%s->",p->pname);p = p->next;}printf("%s\n",p->pname);}void printCQ(PCB* chead,PCB* ctail)    //打印当前已完成进程队列{PCB* p = chead;printf("=> ");if(chead==NULL){//已完成进程队列队列已空printf("空\n");return ;}while(p!=ctail){printf("%s->",p->pname);p = p->next;}printf("%s\n",p->pname);}void printJQ(Job* jhead)    //打印当前后备队列{Job* p = jhead;printf("=> ");if(jhead==NULL){printf("空\n");return ;}while(p->next!=NULL){printf("%s->",p->jname);p = p->next;}printf("%s\n",p->jname);}void getJobName(int i,char name[])    //获得当前进程名 {//进程名strcpy(name,"Job");int len = strlen(name);name[len] = '0'+i;name[len+1] = '\0';}void printProInfo(PCB* now)    //打印当前进程信息{if(now==NULL){printf("当前没有进程\n");return ;}printf("# 当前进程为\n");printf("进程名:%s\n",now->pname);printf("运行时间:%d\n",now->time);printf("进程状态:%c\n",now->status);}void printAllJobInfo(Job* jhead)    //输出所有作业信息{Job* p = jhead->next;printf("\t--- 作业调度表 ---\n");printf("作业名\t");printf("到达时间\t");printf("工作时间\n");while(p!=NULL){printf("%s\t",p->jname);printf("%d\t\t",p->start);printf("%d\n",p->worktime);p = p->next;}}void printQueueInfo(Job *jobtable,Job *jhead,PCB *head,PCB *rhead,PCB *chead,int tablenum,int houbeinum,int readynum)    //打印所有队列信息{printf("\n");printf("--- 运行队列 & 就绪队列 & 已完成队列 ---\n");printf("进程名\t\t");printf("运行时间\t");printf("进程状态\t");printf("\n");PCB *p = NULL;//输出运行队列信息if(readynum!=0){p = rhead;printf("%s\t",p->pname);printf("%d\t\t",p->time);printf("%c\t",'W');printf("\n");}//输出就绪队列信息if(readynum!=0){p = head->next;while(p!=head){printf("%s\t",p->pname);printf("%d\t\t",p->time);printf("%c\t",p->status);printf("\n");p = p->next;}}//输出完成队列if(chead!=NULL){    //完成队列不为空p = chead;while(p!=chead){printf("%s\t",p->pname);printf("%d\t\t",p->time);printf("%c\t",p->status);printf("\n");p = p->next;}}printf("\n");printf("\t--- 后备队列 ---\n");printf("作业名\t");printf("到达时间\t");printf("工作时间\t");printf("\n");Job *q;//输出后备队列if(houbeinum!=0){q = jhead;while(q!=NULL){printf("%s\t",q->jname);printf("%d\t\t",q->start);printf("%d\t",q->worktime);printf("\n");q = q->next;}}printf("\n");printf("\t--- 作业调度表 ---\n");printf("作业名\t");printf("到达时间\t");printf("工作时间\t");printf("\n");//输出作业调度表if(tablenum!=0){q = jobtable->next;while(q!=NULL){printf("%s\t",q->jname);printf("%d\t\t",q->start);printf("%d\t",q->worktime);printf("\n");q = q->next;}}printf("\n");}void printQueueInfo2(PCB *head,PCB *chead,PCB *ctail,Job *jhead,int readynum)    //打印所有队列信息,第二形态,队列式{printf("\n");printf("# 就绪队列:\n");printRQ(head,readynum);printf("# 已完成进程队列:\n");printCQ(chead,ctail);printf("# 后备队列:\n");printJQ(jhead);printf("------------------------------------------------------\n");}int main(){PCB *head=NULL,*tail=NULL;    //就绪队列PCB *rhead=NULL;    //运行队列(运行队列中节点数始终<=1)PCB *chead=NULL,*ctail=NULL;    //已完成进程队列Job *jhead=NULL;    //后备队列Job *jobtable = new Job;    //作业调度表jobtable->next = NULL;int i;int tablenum=0;    //作业调度表中作业数量int houbeinum=0;    //后备队列的作业数量int readynum=0;    //就绪队列进程数//将结果输出到日志文件//freopen("ProcessScheduingLog.log","w",stdout);//初始化srand((unsigned)time(0));    //设置种子for(i=1;i<=JOBSUM;i++){        //初始化每一个进程 char name[40];getJobName(i,name);    //获得作业名if(!CreateJob(jobtable,name)){    //随机创建一个新作业,放入作业调度表中,作业调度表中作业是无序的。printf("Error 1!\n");    //出现错误,直接退出return 0;}else{    //创建成功tablenum++;}}//输出所有作业信息printAllJobInfo(jobtable);printf("\n");printf("# 开始时间片轮转\n");printf("\n");printf("------------------------------------------------------\n");int curtime = 0;    //系统计时域,运行过的时间片个数//时间片轮转进程调度while(readynum!=0 || houbeinum!=0 || tablenum!=0){    //直到就绪队列为空 且 后备队列为空 且 作业调度表为空,退出循环curtime++;    //计时+1printf("当前系统时间 : %d\n",curtime);printf("\n");//先检查作业调度表,有到达作业,放入后备队列bool isArrive = false;Job* p = jobtable->next;while(p!=NULL){if(p->start==curtime){    //有作业到达,将作业放入后备队列,并按短作业优先放置isArrive = true;Job *t = p->next;printf("# 将作业%s投入到后备队列\n",p->jname);AddHoubei(jobtable,p,jhead);                houbeinum++;    //后背队列tablenum--;    //作业调度表p = t;}else{p = p->next;}}if(!isArrive){printf("# 无作业到达\n");}//检查就绪队列是否已满。不满,则将后备队列队首放入就绪队列。if(readynum==JOBNUM){    //已满}else{    //未满,从后备队列中将作业放入就绪队列if(houbeinum!=0){    //后备队列不为空CreateProcess(head,tail,jhead);    //将作业投入到就绪队列printf("# 将作业%s投入到就绪队列\n",jhead->jname);jhead = jhead->next;    //指向后备队列下一个作业readynum++;    //就绪队列houbeinum--;    //后备队列}//已空就算了}PCB* now = head;if(now!=NULL){    //当前就绪队列不为空时运行进程//将该进程放入运行队列rhead = now;//printf("将当前进程放入运行队列\n");printQueueInfo(jobtable,jhead,head,rhead,chead,tablenum,houbeinum,readynum);    //打印所有队列信息Work(now);    //执行当前进程if(now->time==0){now->status = 'C';    //设置进程为已完成状态printf("# 进程%s已完成,退出就绪队列\n",now->pname);DropPro(head,tail,chead,ctail);    //推出循环就绪队列readynum--;if(readynum==0){head = 0;tail = 0;}}else{NextPro(head,tail);    //已完成,将其置于循环队列尾端。即将head和tail向前推进一次}}printQueueInfo2(head,chead,ctail,jhead,readynum);getchar();}curtime++;    //计时+1printf("当前系统时间 : %d\n",curtime);printQueueInfo(jobtable,jhead,head,rhead,chead,tablenum,houbeinum,readynum);    //打印所有队列信息printQueueInfo2(head,chead,ctail,jhead,readynum);return 0;}

说明

  1. 设计进程控制块PCB的结构,分别适用于优先权调度算法和时间片轮转调度算法。
  2. 建立进程就绪队列。
  3. 编制两种进程调度算法:优先调度和时间片调度算法。
    4.操作步骤:
    ① 本程序用两种算法对5个进程进行调度,每个进程可有三个状态,并假设初始状态就是就绪状态。
    ② 为了便于处理,程序中的某进程的运行时间以时间片为单位计算。各进程的优先数或轮转时间数以及进程运行的时间片数的初始值均由用户给定。
    ③ 在优先权算法中,优先数可以先取值为50,进程每执行一次,优先数减3,CPU时间片数加1,进程还需要的时间片数减1。在时间片轮转调度算法中,采用固定时间片(每执行一次进程,该进程的执行时间片数为已执行了2个单位),这时,CPU时间片数加2,进程还需的时间片数减2,并将该进程排列到就绪队列的尾上。
    ④ 对于优先数相同的情况,采用FCFS的策略。

三、银行家算法

实验目的

  1. 理解银行家算法。
  2. 掌握进程安全性检查的方法及资源分配的方法。

代码

#include<stdio.h>
#define resourceNum 4
#define processNum  5//系统可用(剩余)资源
int available[resourceNum]={1,5,2,0};
//进程的最大需求
int maxRequest[processNum][resourceNum]={{0,0,1,2},{1,7,5,0},{2,3,5,6},{0,6,5,2},{0,6,5,6}};
//进程已经占有(分配)资源
int allocation[processNum][resourceNum]={{0,0,1,2},{1,0,0,0},{1,3,5,4},{0,6,3,2},{0,0,1,4}};
//进程还需要资源
int need[processNum][resourceNum]={{0,0,0,0},{0,7,5,0},{1,0,0,2},{0,0,2,0},{0,6,4,2}};
//是否安全
bool Finish[processNum];
//安全序列号
int safeSeries[processNum]={0,0,0,0,0};
//进程请求资源量
int request[resourceNum];
//资源数量计数
int num;//打印输出系统信息
void showInfo()
{int j;printf("\n------------------------------------------------------------------------------------\n");  printf("当前系统各类资源剩余:");for(int j = 0; j < resourceNum; j++){printf("%d ",available[j]);}printf("\n\n当前系统资源情况:\n");printf(" PID\t Max\t\tAllocation\t Need\n");for(int i = 0; i < processNum; i++){printf(" P%d\t",i);for(int j = 0; j < resourceNum; j++){printf("%2d",maxRequest[i][j]);}printf("\t\t");for(j = 0; j < resourceNum; j++){printf("%2d",allocation[i][j]);}printf("\t\t");for(j = 0; j < resourceNum; j++){printf("%2d",need[i][j]);}printf("\n");}
}//打印安全检查信息
void SafeInfo(int *work, int i)
{int j;printf(" P%d\t",i);for(j = 0; j < resourceNum; j++){printf("%2d",work[j]);}   printf("\t\t");for(j = 0; j < resourceNum; j++){printf("%2d",allocation[i][j]);}printf("\t\t");for(j = 0; j < resourceNum; j++){printf("%2d",need[i][j]);}printf("\t\t");for(j = 0; j < resourceNum; j++){printf("%2d",allocation[i][j]+work[j]);}printf("\n");
}//判断一个进程的资源是否全为零
bool isAllZero(int kang)
{num = 0;for(int i = 0; i < resourceNum; i++ ){if(need[kang][i] == 0){num ++;}}if(num == resourceNum){return true;}else{return false;}
}//安全检查
bool isSafe()
{int i;//int resourceNumFinish = 0;int safeIndex = 0;int allFinish = 0;int work[resourceNum] = {0};int r = 0;int temp = 0;int pNum = 0;//预分配为了保护available[]for(int i = 0; i < resourceNum; i++){       work[i] = available[i];    }//把未完成进程置为falsefor(i = 0; i < processNum; i++){bool result = isAllZero(i);if(result == true){Finish[i] = true;allFinish++;}else{Finish[i] = false;}}//预分配开始while(allFinish != processNum){num = 0;  for(i = 0; i < resourceNum; i++){if(need[r][i] <= work[i] && Finish[r] == false){num ++;}         }if(num == resourceNum){      for(i = 0; i < resourceNum; i++ ){work[i] = work[i] + allocation[r][i];}allFinish ++;SafeInfo(work,r);safeSeries[safeIndex] = r;safeIndex ++;Finish[r] = true;}r ++;//该式必须在此处   if(r >= processNum){r = r % processNum;if(temp == allFinish){break;  }temp = allFinish;}        pNum = allFinish;} //判断系统是否安全for(i = 0; i < processNum; i++){if(Finish[i] == false){printf("\n当前系统不安全!\n\n");return false;    }}//打印安全序列printf("\n当前系统安全!\n\n安全序列为:");for(i = 0; i < processNum; i++){  bool result = isAllZero(i);if(result == true){       pNum --;}   }for(i = 0; i < pNum; i++){printf("%d ",safeSeries[i]);}return true;
}//主函数
int  main()
{int i;int curProcess = 0;int a = -1;showInfo(); printf("\n系统安全情况分析\n");printf(" PID\t Work\t\tAllocation\t Need\t\tWork+Allocation\n");bool isStart = isSafe();//用户输入或者预设系统资源分配合理才能继续进行进程分配工作while(isStart){//限制用户输入,以防用户输入大于进程数量的数字,以及输入其他字符(乱输是不允许的)do{ if(curProcess >= processNum || a == 0){printf("\n请不要输入超出进程数量的值或者其他字符:\n");while(getchar() != '\n'){};//清空缓冲区   a = -1;}printf("\n------------------------------------------------------------------------------------\n");printf("\n输入要分配的进程:");a = scanf("%d",&curProcess);printf("\n");}while(curProcess >= processNum || a == 0);//限制用户输入,此处只接受数字,以防用户输入其他字符(乱输是不允许的)for(int i = 0; i < resourceNum; i++){do{if(a == 0){printf("\n请不要输入除数字以外的其他字符,请重新输入:\n");while(getchar() != '\n'){};//清空缓冲区   a = -1;}printf("请输入要分配给进程 P%d 的第 %d 类资源:",curProcess,i+1);a = scanf("%d", &request[i]);}while( a == 0);}//判断用户输入的分配是否合理,如果合理,开始进行预分配num  = 0;for(i = 0; i < resourceNum; i++){if(request[i] <= need[curProcess][i] && request[i] <= available[i]){num ++;}else{printf("\n发生错误!可能原因如下:\n(1)您请求分配的资源可能大于该进程的某些资源的最大需要!\n(2)系统所剩的资源已经不足了!\n");break;}}if(num == resourceNum){   num = 0;   for(int j = 0; j < resourceNum; j++){//分配资源available[j] = available[j] - request[j];allocation[curProcess][j] = allocation[curProcess][j] + request[j];need[curProcess][j] = need[curProcess][j] - request[j];//记录分配以后,是否该进程需要值为0了if(need[curProcess][j] == 0){num ++;}}//如果分配以后出现该进程对所有资源的需求为0了,即刻释放该进程占用资源(视为完成)if(num == resourceNum){//释放已完成资源for(int i = 0; i < resourceNum; i++ ){available[i] = available[i] + allocation[curProcess][i];}printf("\n\n本次分配进程 P%d 完成,该进程占用资源全部释放完毕!\n",curProcess);}else{//资源分配可以不用一次性满足进程需求printf("\n\n本次分配进程 P%d 未完成!\n",curProcess);}showInfo();printf("\n系统安全情况分析\n");printf(" PID\t Work\t\tAllocation\t Need\t\tWork+Allocation\n");//预分配完成以后,判断该系统是否安全,若安全,则可继续进行分配,若不安全,将已经分配的资源换回来if(!isSafe()){           for(int j = 0; j < resourceNum; j++){available[j] = available[j] + request[j];allocation[curProcess][j] = allocation[curProcess][j] - request[j];need[curProcess][j] = need[curProcess][j] +request[j];}printf("资源不足,等待中...\n\n分配失败!\n");                }}}
}

说明

编制模拟银行家算法的程序,并以下面给出的例子验证所编写程序的正确性。
例3-1,某进程有A、B、C、D四种资源供5个进程(P0,P1,P2,P3,P4)共享,各进程对资源的请求和分配情况如表所示。

  1. 现在系统是否处于安全状态;
  2. 如果现在进程P1提出需求(0、4、2、0)资源请求,系统是否能满足它的请求?

四、虚拟存储器管理

实验目的

  1. 理解虚拟存储器概念。
  2. 掌握分页式存储管理地址转换和缺页中断。

代码

#include<cstdio>
#include<cstring>
#define SizeOfPage 100
#define SizeOfBlock 128
#define M 4
struct info//页表信息结构体
{bool flag; //页标志,1表示该页已在主存,0表示该页不在主存long block;//块号long disk;//在磁盘上的位置bool dirty;//更新标志
}pagelist[SizeOfPage];
long po;//队列标记
long P[M];//假设内存中最多允许M=4个页面
void init_ex1()  //内存空间初始化。
{memset(pagelist,0,sizeof(pagelist));  /*分页式虚拟存储系统初始化*/pagelist[0].flag=1;               pagelist[0].block=5;///pagelist[0].disk=011;pagelist[1].flag=1;pagelist[1].block=8;///pagelist[1].disk=012;pagelist[2].flag=1;pagelist[2].block=9;//pagelist[2].disk=013;pagelist[3].flag=1;pagelist[3].block=1;pagelist[3].disk=021;
}
void work_ex1()   //模拟分页式存储管理中硬件的地址转换和产生缺页中断过程
{bool stop=0;long p,q;char s[128];do{printf("请输入指令的页号和单元号:\n");if(scanf("%ld%ld",&p,&q)!=2){scanf("%s",s);if(strcmp(s,"exit")==0)    //如果输入的为"exit"那么就退出,进入重选页面{stop=1;              }}else{if(pagelist[p].flag)         //如果该页flag标志位为1,说明该页在主存中{printf("绝对地址=%ld\n",pagelist[p].block*SizeOfBlock+q);  //计算出绝对地址,绝对地址=块号block×块长(默认128)+单元号///}else{printf("*%ld\n",p);     //如果该页flag标志位为0,表示该页不在主存中,则产生了一次缺页中断}}}while(!stop);
}
void init_ex2()
{/*用先进先出(FIFO)页面调度算法处理缺页中断的初始化,其中也包含了对于当前的存储器内容的初始化*/po=0;P[0]=0;P[1]=1;P[2]=2;P[3]=3;   /对内存中的4个页面进行初始化,并使目前排在第一位的为0///memset(pagelist,0,sizeof(pagelist));//内存空间初始化。pagelist[0].flag=1;pagelist[0].block=5;///pagelist[0].disk=011;pagelist[1].flag=1;pagelist[1].block=8;//pagelist[1].disk=012;pagelist[2].flag=1;pagelist[2].block=9;pagelist[2].disk=013;pagelist[3].flag=1;pagelist[3].block=1;//pagelist[3].disk=021;
}
void work_ex2()        //模拟FIFO算法的工作过程
{long p,q,i;char s[100];bool stop=0;do {printf("请输入指令的页号、单元号,以及是否为内存指令:\n");if(scanf("%ld%ld",&p,&q)!=2){scanf("%s",s);if(strcmp(s,"exit")==0)//如果输入的为"exit"那么就退出,进入重选页面{stop=1;}}else{scanf("%s",s);if(pagelist[p].flag)//如果该页flag标志位为1,说明该页在主存中{printf("绝对地址=%ld\n",pagelist[p].block*SizeOfBlock+q);///计算绝对地址,绝对地址=块号block×块长(128)+单元号/if(s[0]=='Y'||s[0]=='y')//内存指令,在该程序中,无实质性作用{pagelist[p].dirty=1;//修改标志为1}}else//如果所输入的页不在内存中{if(pagelist[P[po]].dirty)       //当前的页面被更新过,需把更新后的内容写回外存{pagelist[P[po]].dirty=0;//将标志位复0}pagelist[P[po]].flag=0;   //将flag标志位置0,表示当前页面已被置换出去printf("out%ld\n",P[po]); //显示根据FIFO算法被置换出去的页面printf("in%ld\n",p);      //显示根据FIFO算法被调入的页面,此时将调入的页置于换出页的位置、、、、、、pagelist[p].block=pagelist[P[po]].block;//将换出页的块号赋给调入页pagelist[p].flag=1; //将当前页面的标记置为1,表示已在主存中P[po]=p;   //保存当前页面所在的位置po=(po+1)%M;  }}}while(!stop);printf("数组P的值为:\n");for(i=0;i<M;i++)     //循环输出当前数组的数值,即当前在内存中的页面{printf("P[%ld]=%ld\n",i,P[i]);}
}
void select()       //选择哪种方法进行
{long se;char s[128];do{printf("请选择题号(1/2):");if(scanf("%ld",&se)!=1){scanf("%s",&s);if(strcmp(s,"exit")==0)  //如果输入为exit则退出整个程序{return;}}else{if(se==1)      //如果se=1,说明选择的是模拟分页式存储管理中硬件的地址转换和产生缺页中断{init_ex1();   //调用init_ex1子函数,初始化work_ex1();   //进行模拟}if(se==2)      //如果se=2说明选择的是FIFO算法来实现页面的置换{init_ex2();  //初始化work_ex2();  //进行模拟}}}while(1);
}
int main()
{select();      //调用select函数,选择题号return 0;
}

说明

本代码当页号为4及以上会产生中断

  1. 模拟分页是存储管理中硬件的地址转换和产生缺页中断。
  2. 用先进先出页面调度算法处理缺页中断。
    具体要求:设计一个“地址转换”程序来模拟硬件的地址转换工作
    当访问的页在主存时,形成绝对地址,但不去模拟指令的执行,而用输出转换后的地址来代替一条指令的执行。当访问的页不在主存中时,则输出“*页号”,表示产生一次缺页中断

    地址转换

    FIFO页面调度

五、设备管理

实验目的

  1. 理解设备管理的概念和任务。
  2. 掌握独占设备的分配、回收等主要算法的原理并编程实现。

代码

#include "iostream"
#include "string"
#include "vector"
using namespace std;
typedef struct node
{string ID;      //进程名string equipment;    //申请的设备名struct node *next;   }PCB;
typedef struct
{string channelID;    //通道标识符bool state;      //通道状态PCB *use;      //正在使用该通道的进程PCB *blockqueue;    //阻塞队首
}CHCT;
typedef struct
{string controllerID;   //控制器标示bool state;      //控制器状态CHCT *front;     //通道表指针PCB *use;      //正在使用该控制器的进程PCB *blockqueue;    //阻塞队首
}COCT;
typedef struct
{char type;      //设备类型string equipmentID;    //设备名bool state;      //设备状态COCT *front;     //控制器指针PCB *use;      //正在使用该设备的进程PCB *blockqueue;    //阻塞队首
}DCT;
typedef struct
{char type;      //设备类型string equipmentID;    //设备名DCT *dct;      //设备的DCT
}SDT;
DCT *k=new DCT;      //键盘的DCT
DCT *m=new DCT;      //mouse
DCT *p=new DCT;     //printer
DCT *t=new DCT;   // 显示
COCT *c1=new COCT;  //control
COCT *c2=new COCT;
COCT *c3=new COCT;
CHCT *h1=new CHCT;   //channel
CHCT *h2=new CHCT;
CHCT *h3=new CHCT;int check(char cmd)
{ switch(cmd){case 'c':       //申请return 1;case 'C':return 1;case 'd':       //删除return 2;case 'D':return 2;case 'a':       //添加return 3;case 'A':return 3;case 'f':       //释放   freereturn 4;case 'F':return 4;case 'q':return -1;case 'Q':return -1;case 'p':return 5;case 'P':return 5;default:return 0;}
}void init(vector<SDT> &SDT_table)
{SDT_table[0].equipmentID="M";SDT_table[0].type='2';     //鼠标是第二类设备SDT_table[0].dct=m;     //设备的DCT表位置SDT_table[1].equipmentID="K";SDT_table[1].type='1';SDT_table[1].dct=k;SDT_table[2].equipmentID="P";SDT_table[2].type='3';SDT_table[2].dct=p;SDT_table[3].equipmentID="T";SDT_table[3].type='4';SDT_table[3].dct=t;h1->blockqueue=NULL;h1->channelID="通道1";h1->state=true;h1->use=NULL;h2->blockqueue=NULL;h2->channelID="通道2";h2->state=true;h2->use=NULL;c1->blockqueue=NULL;c1->controllerID="控制器1";c1->state=true;c1->front=h1;c1->use=NULL;c2->blockqueue=NULL;c2->controllerID="控制器2";c2->state=true;c2->front=h1;c2->use=NULL;c3->blockqueue=NULL;c3->controllerID="控制器3";c3->state=true;c3->front=h2;c3->use=NULL;k->blockqueue=NULL;k->equipmentID="K";k->state=true;      //可用k->type='1';k->front=c1;k->use=NULL;m->blockqueue=NULL;m->equipmentID="M";m->state=true;m->type='2';m->front=c1;m->use=NULL;p->blockqueue=NULL;p->equipmentID="P";p->state=true;p->type='3';p->front=c2;p->use=NULL;t->blockqueue=NULL;t->equipmentID="T";t->state=true;t->type='4';t->front=c3;t->use=NULL;
}
int main()
{char cmd;DCT *temp_dct;COCT *temp_coct;CHCT *temp_chct;int l=0;string ID;string name;vector<SDT> SDT_table(4);      //设备表vector<DCT> DCT_table(4);      //设备vector<COCT> COCT_table(3);      //控制器表
// vector<SDT>::size_type size_SDT_table;   //设备表长度init(SDT_table);   //设备表的初始化   DCT u=*k;DCT_table.push_back(u);u=*m;DCT_table.push_back(u);u=*p;DCT_table.push_back(u);u=*t;DCT_table.push_back(u);COCT cu=*c1;COCT_table.push_back(cu);cu=*c2;COCT_table.push_back(cu);cu=*c3;COCT_table.push_back(cu);cout<<"目前设备:K:键盘(1)    M:鼠标(2)     P:打印机(3)     T:显示器(4)"<<endl;cout<<"操作指令C 申请使用设备。"<<endl;cout<<"操作指令D 删除设备。"<<endl;cout<<"操作指令A 添加设备。"<<endl;cout<<"操作指令F 释放设备。"<<endl;while(l!=-1){ cout<<">";cin>>cmd;l=check(cmd);if(l==0){cout<<"指令错误请重新输入。"<<endl;continue;}else if(l==1)       //申请使用设备{cout<<"想要使用的设备名:"<<endl;cin>>ID;cout<<"申请设备的进程名:"<<endl;cin>>name;PCB *head=new PCB;     //申请PCB的创建和链接head->equipment=name;head->ID=ID;head->next=NULL;bool find=false;vector<SDT>::iterator ator0;for(ator0=SDT_table.begin();ator0!=SDT_table.end();ator0++){if(ator0->equipmentID==ID){find=true;      //有该设备break;}}if(!find){cout<<"没有该设备,请重新输入操作指令。"<<endl;continue;}temp_dct=ator0->dct;if(!temp_dct->state)    //设备忙{cout<<"该设备目前处于忙状态,已经把请求加入等待队列。"<<endl;if(!temp_dct->blockqueue)     //阻塞的队列为空{temp_dct->blockqueue=head;}else           //阻塞队列已经有内容{PCB* t=temp_dct->blockqueue;while(t)t=t->next;if(!t){temp_dct->blockqueue=NULL;}elset->next=head;}}else        //设备空闲{temp_coct=temp_dct->front;temp_dct->state=false;temp_dct->use=head;     //添加正在占用设备的进程if(!temp_coct->state)    //控制器不可用{cout<<"目前该设备连接的控制器忙,已经把请求加入等待队列."<<endl;if(!temp_coct->blockqueue)    //阻塞的队列为空{temp_coct->blockqueue=head;}else     //阻塞队列不空{PCB* t=temp_coct->blockqueue;while(t)t=t->next;if(!t){temp_dct->blockqueue=NULL;}elset->next=head;}}else     //控制器可用{temp_coct->state=false;   //控制器置忙temp_chct=temp_coct->front;temp_coct->use=head;if(!temp_chct->state)    //通道不可用{cout<<"目前该设备连接的通道忙,已经把请求加入等待队列."<<endl;if(!temp_chct->blockqueue)  //阻塞队列为空{temp_chct->blockqueue=head;}else       //阻塞队列不为空{PCB* t=temp_coct->blockqueue;while(t)t=t->next;if(!t){temp_dct->blockqueue=NULL;}elset->next=head;}}else        //通道可用{temp_chct->use=head;temp_chct->state=false;   //通道状态置忙cout<<"该设备已经成功申请,请输入下一条指令."<<endl;}}}}else if(l==2)      //删除设备{vector<SDT>::iterator ator;vector<DCT>::iterator ator1;cout<<"现在系统拥有的设备如下:"<<endl;for(ator=SDT_table.begin();ator!=SDT_table.end();ator++){cout<<ator->equipmentID<<"  ";}cout<<"请输入想要删除的设备名:";cin>>name;for(ator=SDT_table.begin();ator!=SDT_table.end();ator++){if(ator->equipmentID==name)    //查找到了该设备{ator1=ator->dct;COCT *temp=ator1->front;ator->dct=NULL;SDT_table.erase(ator);   //从设备表中删除ator=SDT_table.begin();
/*for(ator=SDT_table.begin();ator!=SDT_table.end();ator++)cout<<ator->equipmentID<<"  ";cout<<endl;
*/     if(temp->use){if(temp->use->equipment==name)   //该设备正在占用控制器{if(!temp->blockqueue)   //控制器的等待队列为空{temp->state=true;temp->use=NULL;}else     //控制器的等待队列有内容{PCB *tt=temp->blockqueue;temp->blockqueue->next=tt->next;temp->use=tt;tt->next=NULL;}}else      //该设备没有占用控制器{temp->blockqueue=NULL;}}ator1->blockqueue=NULL;ator1->front=NULL;ator1->use=NULL;vector<DCT>::iterator ator2;vector<DCT> D;for(ator2=DCT_table.begin();ator2!=DCT_table.end();ator2++){if(ator2!=ator1)D.push_back(*ator2);}DCT_table=D;
//     ator1=DCT_table.erase(ator1);    //删除该设备break;}}if(ator==SDT_table.end())  //判断是否查找到设备{cout<<"没有该设备,请重新输入操作指令"<<endl;}else{cout<<"成功删除该设备,请输入下一条操作指令。"<<endl;}}else if(l==3)      //添加设备{SDT SDT_add;DCT DCT_add;int select;cout<<"输入要添加的设备名称:";cin>>DCT_add.equipmentID;SDT_add.equipmentID=DCT_add.equipmentID;cout<<"输入设备的类型(单个数字或单个字母):";cin>>DCT_add.type;SDT_add.type=DCT_add.type;SDT_add.dct=&DCT_add;DCT_add.blockqueue=NULL;DCT_add.use=NULL;DCT_add.state=true;SDT_table.push_back(SDT_add);DCT_table.push_back(DCT_add);cout<<"是否需要新增控制器:    1.新增         2.使用已存在的"<<endl;cin>>select;if(select==1)     //新增{COCT c;c.blockqueue=NULL;c.state=true;cout<<"输入控制器的名称(如:控制器1):";cin>>c.controllerID;c.use=NULL;DCT_add.front=&c;cout<<"1."<<h1->channelID<<'\t'<<"2."<<h2->channelID<<endl;cout<<"链接到哪个通道:";cin>>select;if(select==1)       //链接到两个不同的通道{c.front=h1;}else{c.front=h2;}cout<<"连接成功."<<endl;COCT_table.push_back(c); }else       //利用以前的控制器{for(vector<COCT>::iterator ator=COCT_table.begin();ator!=COCT_table.end();ator++)    //输出现有控制器名称{cout<<ator->controllerID<<endl;}          cout<<"选择的控制器名是(如:控制器1):";cin>>name;for(ator=COCT_table.begin();ator!=COCT_table.end();ator++)    //按名字进行选择{if(ator->controllerID==name){DCT_add.front=ator;cout<<"链接成功,请输入下一条指令."<<endl;break;}}}}else if(l==4)      //释放设备资源{cout<<"想要释放的设备名:";cin>>name;DCT *DCT_temp;     //暂存DCTCOCT *COCT_temp;    //暂存COCTCHCT *CHCT_temp;    //暂存CHCTfor(vector<SDT>::size_type i=0;i<SDT_table.size();i++){if(SDT_table[i].equipmentID==name){DCT_temp=SDT_table[i].dct;COCT_temp=DCT_temp->front;CHCT_temp=COCT_temp->front;if(!DCT_temp->use)     //如果该设备没有被使用{cout<<"该设备未被占用,无需释放。"<<endl;break;}else        //设备现在被占用{if(CHCT_temp->use->ID==name)  //该设备目前占用通道时{if(!CHCT_temp->blockqueue)   //通道的等待队列无内容{CHCT_temp->state=true;CHCT_temp->use=NULL;}else        //通道的等待队列不为空{CHCT_temp->use=CHCT_temp->blockqueue;CHCT_temp->blockqueue=CHCT_temp->blockqueue->next;}}if(COCT_temp->use->ID==name)   //设备占用控制器{if(!COCT_temp->blockqueue)    //控制器的等待队列为空{COCT_temp->use=NULL;COCT_temp->state=true;}else        //控制器等待队列有内容{COCT_temp->use=COCT_temp->blockqueue;COCT_temp->blockqueue=COCT_temp->blockqueue->next;}}if(!DCT_temp->blockqueue)     //设备自身的等待队列{   //为空DCT_temp->state=true;DCT_temp->use=NULL;break;}else      //该设备目前被其他进程申请(队列不空){DCT_temp->use=DCT_temp->blockqueue;DCT_temp->blockqueue=DCT_temp->blockqueue->next;break;}if(!COCT_temp->use){COCT_temp->use=DCT_temp->use;COCT_temp->state=false;if(!CHCT_temp->use){CHCT_temp->use=COCT_temp->use;CHCT_temp->state=false;}}}}}   if(i==SDT_table.size()){cout<<"该设备不存在,请重新输入下一条操作指令。"<<endl;}else{cout<<"成功释放该设备,请输入下一条指令。"<<endl;}}
}
return 0;
}

说明

系统为每一个设备都配置了一张设备控制表,用于记录本设备的情况,每一设备占一个表目,包括:设备状态、是否分配、占有作业名等。
作业申请某设备时,先查“设备类表”,如果该类设备所拥有的设备数量满足申请要求,则从设备类表中得到该类设备的设备表起始地址,然后找到“设备控制表”中该类设备的起始地址,依次查询该类设备的表项,找到设备是“好”且没有被分配的设备分配给作业。分配设备的过程中要修改“设备类表”中可分配设备的数量,并且把“设备控制表”中的“是否分配”项更改为“是”,并填写占有作业名和相对号。
设备回收时,系统首先查看设备控制表,找到需要释放的设备,将该设备“是否分配”项更改为“否”,然后在设备类表中将“可分配设备数量”加1。

代码下载链接: 传送门

以下为12.25更新的最后一次代码

实验六 spooling技术

实验目的

理解和掌握SPOOLING假脱机技术。

代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<iostream>
using namespace std;
struct REQ{int ioblock_id;//要求输出进程标识数int block_len;//本次输出长度int block_start;//本次输出的首地址REQ* next;
};
REQ *head=NULL,*tail=NULL;
struct PCB{int id;//进程标识数int state;//进程状态REQ* point;//输出指针(指向上次断点)int start;//信息块首地址int length;//输出长度int buffer;//输出缓冲字(-1表示没有断点)};
PCB pcb[2];
FILE *f;
int freeioblock=10;//空闲输出请求块计数器
int freepoollen[2]={100,100};//两个输出井的计数器
int count[2];//用来控制两个请求输出进程的输出文件数,避免系统无限制循环下去
int buffer[2][100];
/*
0 可运行状态
1 不可运行状态1(输出井满)
2 不可运行状态2(无请求块)
3 结束状态
*/void init();
void scheduler();
void userproc(int i);
void spooling();int main()
{init();scheduler();cout<<endl;cout<<"buffer[0] "<<endl;for(int m=0;m<100;m++){if(m%10==0)cout<<endl;cout<<buffer[0][m];}cout<<endl;cout<<"buffer[1] "<<endl;for(int mm=0;mm<100;mm++){if(mm%10==0)cout<<endl;cout<<buffer[1][mm];}return 0;
}void init()
{int i,n;f=fopen("out.txt","w");for(i=0;i<2;i++)for(n=0;n<100;n++)buffer[i][n]=0;for(i=0;i<2;i++){pcb[i].id=i;pcb[i].state=0;pcb[i].start=0;pcb[i].buffer=-1;}printf("input the times of user1's output file ");fprintf(f,"input the times of user1's output file ");scanf("%d",&count[0]);fprintf(f,"%d\n",count[0]);printf("input the times of user1's output file ");fprintf(f,"input the times of user1's output file ");scanf("%d",&count[1]);fprintf(f,"%d\n",count[1]);
}
void scheduler()
{int i;srand((unsigned)time(NULL));while(1){i=rand()%100;cout<<endl;cout<<"选择随机数i的值: "<<i<<endl;if(i<=45){if((pcb[0].state==0)&&count[0]>0)userproc(0);}else if(i<=90&&count[1]>0){if(pcb[1].state==0)userproc(1);}elsespooling();if(count[0]==0)pcb[0].state=3;if(count[1]==0)pcb[1].state=3;if(pcb[0].state==3&&pcb[1].state==3)break;}fclose(f);
}void userproc(int i)
{cout<<"in userproc !"<<endl;cout<<"  process "<<i<<": "<<endl;int j;if(freeioblock==0||freepoollen[i]==0)//输出井满或无空闲请求块{if(freepoollen[i]==0)pcb[i].state=1;//输出井满return;}int length=0;if(pcb[i].buffer==-1)//上次输入完成,无断点{cout<<"in first"<<endl;count[i]--;//进程i的工作量-1freeioblock--;//空闲请求块-1REQ* temp=new REQ;temp->ioblock_id=i;temp->next=NULL;for(int m=0;m<100;m++){if(buffer[i][m]==0){//在buffer中找到第一个空闲temp->block_start=m;break;}}if(head==NULL&&tail==NULL){head=temp;tail=temp;}else{//新的请求块插到队尾tail->next=temp;tail=temp;}while(1){j=rand()%10;cout<<j;if(j==0){//结束temp->block_len=length;pcb[i].length+=length;pcb[i].buffer=-1;break;}if(buffer[i][temp->block_start+length+1]==0){//输出井中空余连续buffer[i][temp->block_start+length]=j;freepoollen[i]--;length++;}else{if(freepoollen[i]==0){//输出井满,退出pcb[i].state=1;//状态1 输出井满buffer[i][temp->block_start+length-1]=-1;temp->block_len=length;pcb[i].buffer=j;//记录未完成的输入pcb[i].length+=length;pcb[i].point=temp;//指向断点break;}else{buffer[i][temp->block_start+length]=-1;//表示还未到0,后面没位置,挪位后还可写,不是指输出井满length++;freepoollen[i]--;temp->block_len=length;pcb[i].buffer=j;//记录未完成的输入pcb[i].length+=length;pcb[i].point=temp;//指向断点break;}}}}else{//前面未完成输入,有断点cout<<"in second"<<endl;length=0;freeioblock--;//空闲请求块-1,但count[i]不用减,还是属于上一个工作REQ* temp=new REQ;temp->ioblock_id=i;temp->next=NULL;for(int m=0;m<100;m++){if(buffer[i][m]==0){//寻找输出井中第一个空闲位temp->block_start=m;break;}}REQ *point=pcb[i].point;//恢复断点,将这个新建的请求块插入上次的断点后面if(point->next==NULL){tail->next=temp;tail=temp;}else{//将这个新建的请求块插入上次的断点后面temp->next=point->next;point->next=temp;}while(1){j=rand()%10;cout<<j;if(j==0){//结束temp->block_len=length;pcb[i].length+=length;pcb[i].buffer=-1;break;}if(buffer[i][temp->block_start+length+1]==0){buffer[i][temp->block_start+length]=j;freepoollen[i]--;length++;}else{if(freepoollen[i]==0){//输出井满,退出pcb[i].state=1;//状态1 输出井满buffer[i][temp->block_start+length-1]=-1;pcb[i].buffer=j;//记录未完成的输入temp->block_len=length;pcb[i].length+=length;pcb[i].point=temp;//指向断点break;}else{buffer[i][temp->block_start+length]=-1;//表示还未到0,后面没位置,挪位后还可写,不是指输出井满freepoollen[i]--;length++;pcb[i].buffer=j;//记录未完成的输入temp->block_len=length;pcb[i].length+=length;pcb[i].point=temp;//指向断点break;}}}}cout<<endl;}void spooling()
{cout<<"in spooling !"<<endl;if(freeioblock==10)//无请求块,即请求块全为空闲return;REQ *run=head;REQ *temp=head;int temp_id=head->ioblock_id;int temp_state=pcb[temp_id].state;printf("%d:",run->ioblock_id);fprintf(f,"%d:",run->ioblock_id);int x=buffer[temp_id][run->block_start+run->block_len-1];int flag=0;do{flag=0;for(int i=0;i<temp->block_len;i++){if((buffer[temp_id][temp->block_start+i])!=-1)//没有断{printf("%d",buffer[temp_id][temp->block_start+i]);fprintf(f,"%d",buffer[temp_id][temp->block_start+i]);buffer[temp_id][temp->block_start+i]=0;freepoollen[temp_id]++;}else{//遇到断点flag=1;break;}}REQ* y=temp;temp=temp->next;head=head->next;//头指针向后移y->next=NULL;x=buffer[temp_id][temp->block_start+temp->block_len-1];free(y);//对应的请求块在输出井中的全部内容输入后释放freeioblock++;}while(x==-1);//以当前请求块末尾不为-1为结束条件if(pcb[temp_id].state==1)pcb[temp_id].state=0;}

说明

通过SPOOLING技术可将一台物理I/O设备虚拟成几台逻辑I/O设备,同样允许多个用户共享一台物理I/O设备,从而使其成为虚拟设备。该技术广泛应用于各种计算机I/O设备,通过采用预输入和缓输出的方法,使用共享设备的一部分空间来模拟独占设备,以提高独占设备的利用率。
具体要求:

  1. 设计一个实现Spooling技术的进程
    设计一个Spooling输出进程和两个请求输出的用户进程以及一个Spooling输出服务程序。Spooling输出进程工作时,根据请求块记录的各进程要输出的信息,将其实际输出到打印机或显示器。这里,Spooling进程和请求输出的进程可并发执行。
  2. 设计进程调度算法
    进程调度采用随机算法,这与进程输出信息的随机性相一致。两个请求输出进程的调度概率各为45%,Spooling输出进程调度概率为10%,这由随机数发生器产生的随机数模拟决定。
  3. 进程状态
    进程基本状态有三种,分别为可执行,等待和结束。可执行状态就是进程正在执行或等待调度的状态;等待状态又分为等待状态1,等待状态2和等待状态3。
    状态变化的条件:
    ① 进程执行完成时,置为“结束”状态。
    ② 服务程序在将输出信息送至输出井时,如发现输出井已满,则调用进程置为“等待状态1”。
    ③ Spooling进程在进行输出时,若输出井空,则进入“等待状态2”。
    ④ Spooling进程输出一个信息块后,应立即释放该信息块占用的输出井空间,并将正在等待的输出进程置为“可执行状态”。
    ⑤ 服务程序在输出程序到输出井并形成输出请求信息块后,若Spooling进程处于等待状态则将其置为“可执行状态”。
    ⑥ 当用户进程申请请求输出块时,若没有可用请求块,进程进入“等待状态3”。

更新完毕,需要的可以采用

操作系统课程实验代码汇总相关推荐

  1. 苏州大学计算机学院课程实验代码汇总

    苏州大学计算机学院课程实验代码汇总(持续更新) Python程序设计 点击查看代码集(GitHub) C++程序设计 点击查看代码集(GitHub) 信息检索课程实践 (Python) 点击查看代码集 ...

  2. 哈工大操作系统课程实验记录

    哈工大操作系统课程实验记录 0-课程准备 课程视频地址: https://www.bilibili.com/video/BV1d4411v7u7 实验楼地址: https://www.shiyanlo ...

  3. 课程linux实验报告,Linux操作系统课程实验报告.doc

    Linux操作系统课程实验报告.doc Linux操作系统课程实验报告班级姓名学号指导老师田丽华完成时间2014年7月目录一.实验目的1二.实验要求1三.实验内容1[第一题]1[第二题]2[第三题]4 ...

  4. 电子科技大学---操作系统课程实验(一)

     电子科技大学-操作系统课程实验(一) 系统化思维模式下计算机操作系统进程与资源管理设计 1.实验目的: 设计和实现进程与资源管理,并完成Test shell的编写,以建立系统的进程管理.调度.资源 ...

  5. linux课程实验报告,Linux操作系统课程实验报告

    Linux操作系统课程实验报告 Linux操作系统 课程实验报告 班级: 姓名: 学号: 指导老师:田丽华 完成时间:2014年7月 目录 一.实验目的1 二.实验要求1 三.实验内容1 [第一题]1 ...

  6. C++课程学习代码汇总基础

    写在开头的话:          今天难得一天没课.打算把之前学习过的课程再重新看一遍.写了好多代码,编译运行之后都删掉写下一个了.          久而久之不免觉得浪费,现在把它们都贴在下面把.就 ...

  7. 课程实验代码及动手动脑测试

    枚举类型测试代码: public class EnumTest {public static void main(String[] args) {Size s = Size.SMALL;Size t ...

  8. 清华大学操作系统课程实验

    课程 链接: https://www.bilibili.com/video/av94122925/?spm_id_from=333.788.videocard.0

  9. 操作系统文件管理实验代码

    实现了简单的文件系统的操作. 没有实现磁盘块之间的连接,目录与磁盘属于一对一链接,没法指定磁盘块存放并且文件内容超出磁盘块就无法存储了. #include<iostream> #inclu ...

最新文章

  1. openSUSE中文输入的安装和设置
  2. 践行RONG理念,2018年清华数据院科研成果一隅
  3. SAP 如何看某个TR是否传入了Q或者P系统?
  4. POJ - 3678 Katu Puzzle(2-SAT)
  5. c语言基类型,C语言基本类型边界值
  6. Mac python Tesseract 验证码识别
  7. magento URL分析,查找修改相应文件
  8. 随想录(推荐『步步惊芯 - 软核处理器内部设计分析』这本书)
  9. java 判断文件是否打开过_【后端开发】Java中如何判断文件是否被隐藏?(代码示例)...
  10. python如何读取文本_python 如何读取windows-1252格式文本?
  11. BERT时代,向量语义检索我们关注什么?
  12. 基于差分分级和关联规则挖掘的气象数据关联性分析实战
  13. Android Builder模式
  14. Oracle 中 varchar2 和 mysql 中 varchar到底能存多少个汉字?
  15. windows 弹shell_10个简洁实用的Windows装机必备软件
  16. GOOGLE取消PR值是真是假?
  17. 内存数据网格IMDG简介
  18. 看苹果出的面试难题!!!
  19. android获取短信中心号
  20. WPF 触发器Triggers

热门文章

  1. Linux鼠标变成十字,点击不动
  2. HRESULT 0x80072EE5(VisualSVN Server 报错)
  3. 在线提问回答系统(类似知乎)毕业设计
  4. 荣耀9i 鸿蒙,荣耀9i和荣耀9青春版哪个好 哪个性价比更高?
  5. 【Python3.6爬虫学习记录】(十二)PhantomJS模拟登陆并爬取教务处学生照片(哈工大)
  6. 电脑键盘equals在哪个位置_常用标点符号和电脑键盘符号英语表示
  7. 2020年江苏专转本计算机知识点,2020年江苏专转本计算机真题及答案(供参考).pdf...
  8. 华为上拉添加计算机,华为底部上拉菜单 | 手游网游页游攻略大全
  9. 每日一题 leetcode 997. 找到小镇的法官 java
  10. 24000年来气候分析登Nature,地表气温上升7度,现代变暖速度幅度不同寻常