本次内容供需要有相关实验需要的提供参考,代码下载方式在文末
本次更新的是操作系统课程实验的代码和实验内容
提示:以下是本篇文章正文内容,下面案例可供参考:主要涉及的实验有:1.进程管理、2.进程调度、3.银行家算法、4.虚拟存储器管理、5.设备管理、6、spooling技术
主函数
#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项功能供用户选择,用户通过在界面输入各个功能所对应的标号选择执行不同的功能。
#include
#include
#include
#include
#include
// 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小于或者等于下一个节点的start
Job *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小于或者等于下一个节点的worktime
Job *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设为空NULL
if(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++; //计时+1
printf("当前系统时间 : %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++; //计时+1
printf("当前系统时间 : %d\n",curtime);
printQueueInfo(jobtable,jhead,head,rhead,chead,tablenum,houbeinum,readynum); //打印所有队列信息
printQueueInfo2(head,chead,ctail,jhead,readynum);
return 0;
}
#include
#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];
}
//把未完成进程置为false
for(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)共享,各进程对资源的请求和分配情况如表所示。
#include
#include
#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及以上会产生中断
#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': //释放 free
return 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::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;
}
else
t->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;
}
else
t->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;
}
else
t->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<equipmentID<<" ";
cout<
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; //暂存DCT
COCT *COCT_temp; //暂存COCT
CHCT *CHCT_temp; //暂存CHCT
for(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假脱机技术。
#include
#include
#include
#include
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);
}
else
spooling();
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的工作量-1
freeioblock--;//空闲请求块-1
REQ* 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设备,通过采用预输入和缓输出的方法,使用共享设备的一部分空间来模拟独占设备,以提高独占设备的利用率。
具体要求:
更新完毕,需要的可以采用