操作系统实验指导及实验五个前言1.实验总体目标通过学生自己动手设计实验验证理论知识,使学生掌握操作系统特征和功能,掌握不同调度算法下进程的调度、进程控制、进程调度与死锁,并必须掌握作业管理、存储器管理、设备管理和文件管理的主要原理。
加深对操作系统基本原理理解。
⒉适用专业计算机科学与技术⒊先修课程C语言程序设计、计算机组成原理、数据结构⒋实验课时分配⒌有70台中等配置的计算机组成的小型局域网的实验室环境。
计算机的具体要求:(1)Pentium 133Hz以上的CPU;(2)建议至少256MB的内存;(3)建议硬盘至少2GB,并有1GB空闲空间。
(4)安装Windows操作系统及C语言编译程序或Linux虚拟环境。
⒍实验总体要求培养计算机专业的学生的系统程序设计能力,是操作系统课程的一个非常重要的环节。
通过操作系统上机实验,可以培养学生程序设计的方法和技巧,提高学生编制清晰、合理、可读性好的系统程序的能力,加深对操作系统课程的理解。
使学生更好地掌握操作系统的基本概念、基本原理、及基本功能,具有分析实际操作系统、设计、构造和开发现代操作系统的基本能力。
实验要求做到:1)详细描述实验设计思想、程序结构及各模块设计思路;2)详细描述程序所用数据结构及算法;3)明确给出测试用例和实验结果;4)为增加程序可读性,在程序中进行适当注释说明;5)认真进行实验总结,包括:设计中遇到的问题、解决方法与收获等;6)实验报告撰写要求结构清晰、描述准确逻辑性强;7)实验过程中,同学之间可以进行讨论互相提高,但绝对禁止抄袭。
⒎本实验的重点、难点及教学方法建议重点:理解进程调度中PCB的设计,以实现对进程的调度。
难点:进程调度程序的设计,设备管理程序的设计。
教学方法建议:力争在本指导书的帮助下,独立设计程序以加深理解。
实验一分析操作系统所面临的操作需求(一)实验目的使学生理解操作系统所面临的操作需求,掌握操作系统中的进程管理、存储管理、设备管理和文件管理等功能。
(二)实验内容1. 分析操作系统所面临的操作需求;2. 熟悉实验环境;3. 资料搜集与整理,进行实验的前期准备。
熟悉编程环境本课程中的实验题目既可以在windows下用控制台应用程序实现,也可以在linux下用全屏幕程序实现。
这里我们首先介绍在windows下用vc++6.0设计控制台应用程序的步骤,然后介绍在linux下用C语言编写全屏幕程序的步骤。
1.windows的控制台应用程序图1-1 图1-2图1-3步骤1:开机,单击“开始”按钮,选择“程序->Microsoft Visual Studio 6.0->Microsoft Visual C++6.0”进入Microsoft Visual C++6.0。
见图1-1。
步骤2:在Microsoft Visual C++6.0中,单击“File”菜单,选择“New”菜单命令,见图1-2。
步骤3:在“Files”选项卡中选择“C++ Source File”,见图1-32. linux的vi应用编程登录 Linux是一个多用户多任务操作系统,多个用户可以拥有自己独立的用户账号登录提示:Red Hat Linux release 6.0 (Hedwing)Kernel 2.2.5-15 on an i686Login:此时输入用户户名(账号)并键入回车,则系统显示“passward”。
在输入密码和回车。
登录后:[root@hawk/root]##表示是按root方式登录,$表示是普通用户。
Linux大小写敏感,用“-”加参数zlinux:~# ls –FHowTo/ HowToMin/ linux@ nag/ sag/获取帮助:Linux带有联机手册,可以用man命令来阅读Zlinux:~$ man ls虚拟终端 Linux可有多个用户登录到同一个计算机,但一般微机只有一个终端难以体现。
可以使用多个虚拟终端,用Alt+F1、 Alt+F2等来切换。
退出系统在停止使用系统时,要退出系统。
具体方法:exit或logout,或Ctrl+D关机如果没有用户在使用系统,可以关机。
但是不能直接关闭电源,而要按正常顺序关机。
一般用户是不能关机的,只有root用户可以关机。
方法:可以使用halt或shutdown命令,也可以同时键入Ctrl+Alt+Del。
Windows 虚拟机环境:登录到系统点击桌面“VMware”图标——> Vmware Workstation窗口——>Commands ——>Start this virtual machine进入fedora后,用户名:root口令:123456使用编辑器vi 编辑文件1.进入linux的文本模式之后,在命令行键入vi filename.c 然后回车。
下面作一些简单的解释:首先vi命令是打开vi编辑器。
后面的filename.c 是用户即将编辑的c文件名字,注意扩展名字是.c;当然,vi编辑器功能很强,可以用它来编辑其它格式的文件,比如汇编文件,其扩展名字是.s;也可以直接用vi打开一个新的未命名的文件,当保存的时候再给它命名,只是这样做不很方便。
2.最基本的命令I :当进入刚打开的文件时,不能写入信息,这时按一下键盘上的I键(insert),插入的意思,就可以进入编辑模式了。
如下图所示:3.a与i是相同的用法4.当文件编辑完后,需要保存退出,这时需要经过以下几个步骤:1)按一下键盘上的Esc 键;2)键入冒号(:),紧跟在冒号后面是wq(意思是保存并退出)。
如果不想保存退出,则在第二步键入冒号之后,键入!q(不带w,机尾部保存)。
如下图所示:5.退出vi编辑器的编辑模式之后,要对刚才编写的程序进行编译。
编译的命令是:gcc filename.c [-o outputfilename],其中gcc是c的编译器。
参数:filename.c 是刚才编辑的c 文件(当然也可以是以前编写好的c文件);后面中括号里面的参数是可选的,它是一个输出文件。
如果不选,默认的输出文件是 a.out ,选了之后输出文件就是outputfilename.out.6.最后一步是运行程序,方法如下:./outputfilename.out实验二进程管理(一)实验目的掌握临界区的概念及临界区的设计原则;掌握信号量的概念、PV操作的含义以及应用PV操作实现进程的同步与互斥;分析进程争用资源的现象,学习解决进程互斥的方法;掌握进程的状态及状态转换;掌握常用的进程调度算法。
(二)实验内容1.分析进程的同步与互斥现象,编程实现经典的进程同步问题——生产者消费者问题的模拟;2.编写允许进程并行执行的进程调度程序,在常用的进程(作业)调度算法:先来先服务算法、短作业优先算法、最高响应比优先算法、高优先权优先算法等调度算法中至少选择三种调度算法进行模拟,并输出平均周转时间和平均带权周转时间。
本实验涉及内容较多,可以在两个题目里选择一个完成。
编程实现经典的进程同步问题——生产者消费者问题的模拟模拟实现用同步机构避免发生进程执行时可能出现的与时间有关的错误。
进程是程序在一个数据集合上运行的过程,进程是并发执行的,也即系统中的多个进程轮流地占用处理器运行。
我们把若干个进程都能进行访问和修改的那些变量称为公共变量。
由于进程是并发地执行的,所以,如果对进程访问公共变量不加限制,那么就会产生“与时间有关”的错误,即进程执行后所得到的结果与访问公共变量的时间有关。
为了防止这类错误,系统必须要用同步机构来控制进程对公共变量的访问。
一般说,同步机构是由若干条原语——同步原语——所组成。
本实验要求模拟PV操作同步机构的实现,模拟进程的并发执行,了解进程并发执行时同步机构的作用。
此次用到的数据结构知识如下:typedef struct Pcb{char name[10]; //进程名char state[10]; //运行状态char reason[10]; //若阻塞,其原因int breakp; //断点保护struct Pcb *next; //阻塞时的顺序}Pcb,*link;进程控制块结构定义两个进程: link p1;//生产者进程,link c1;//消费者进程。
pc程序计数器和link ready; 就绪队列,link b_s1; s1阻塞队列,link b_s2; s2阻塞队列。
实验指导:a.h头文件#include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<limits.h> /* INT_MAX等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<io.h> /* eof() */#include<math.h> /* floor(),ceil(),abs() */#include<process.h> /* exit() */#include <iostream>using namespace std;#include <time.h>#define BUF 10 //缓存的大小#define MAX 20 //最大可以输入的字符b.h头文件//数据结构的定义和全局变量typedef struct Pcb{char name[10]; //进程名char state[10]; //运行状态char reason[10]; //若阻塞,其原因int breakp; //断点保护struct Pcb *next; //阻塞时的顺序}Pcb,*link;int s1,s2; //信号量link p1;//生产者进程link c1;//消费者进程char str[MAX]; //输入的字符串char buffer[BUF]; //缓冲池int len; //输入长度int sp=0; //string的指针int in=0; //生产者指针int out=0; //消费者指针char temp; //供打印的临时产品char rec_p[MAX];//生产记录int rp1=0;//生产记录指针char rec_c[MAX];//消费记录int rp2=0;//消费记录指针link ready; //就绪队列link b_s1; //s1阻塞队列link b_s2; //s2阻塞队列int pc; //程序计数器int count; //字符计数器int con_cnt; //消费计数器c.h头文件void init(); //初始化void p(int s); //P操作void v(int s); //V操作void block(int s);//阻塞函数void wakeup(int s);//唤醒函数void control(); //处理机调度void processor();//处理机执行void print(); //打印函数void init(){ //初始化s1=BUF;s2=0;p1=(link)malloc(sizeof(Pcb));//建立新的结点,并初始化为生产者strcpy(p1->name,"Producer");strcpy(p1->state,"Ready");strcpy(p1->reason,"Null");p1->breakp=0;p1->next=NULL;c1=(link)malloc(sizeof(Pcb));//建立新的结点,并初始化为消费者strcpy(c1->name,"Consumer");strcpy(c1->state,"Ready");strcpy(c1->reason,"Null");c1->breakp=0;c1->next=NULL;ready=p1;ready->next=c1;//初始化为生产进程在前,消费进程在后c1->next=NULL;b_s1=NULL;b_s2=NULL;//阻塞进程为NULLpc=0;con_cnt=0; //消费计数器}void p(int s){if(s==1){ //p(s1)s1--;if(s1<0)block(1); //阻塞当前生产进程else{printf("\t* s1信号申请成功!\n");ready->breakp=pc; //保存断点}}else{ //p(s2)s2--;if(s2<0)block(2);//阻塞当前消费进程else{printf("\t* s2信号申请成功!\n");ready->breakp=pc; //保存断点}}}void v(int s){if(s==1){ //v(s1)s1++;if(s1<=0)wakeup(1); //唤醒生产进程ready->breakp=pc; //保存断点}else{ //v(s2)s2++;if(s2<=0)wakeup(2);//唤醒消费进程ready->breakp=pc; //保存断点}}void block(int s){//阻塞函数的定义link p;int num1=0;int num2=0;if(s==1){//生产进程strcpy(p1->state,"Block");//改变状态strcpy(p1->reason,"S1");//说明原因p=b_s1;while(p){num1++;p=p->next;//p的值为NULL,表示队尾}if(!b_s1)b_s1=p1;elsep=p1;p1->next=NULL;printf("\t* p1生产进程阻塞了!\n");ready->breakp=pc; //保存断点ready=ready->next;//在就绪队列中去掉,指向下一个num1++;}else{//消费进程strcpy(c1->state,"Block");strcpy(c1->reason,"S2");p=b_s2;while(p){num2++;p=p->next;//p的值为NULL,表示队尾}if(!b_s2)b_s2=c1;elsep=c1;ready->breakp=pc; //保存断点ready=ready->next;//在就绪队列中去掉,指向下一个c1->next=NULL;printf("\t* c1消费进程阻塞了!\n");num2++;}printf("\t* 阻塞的生产进程个数为:%d\n",num1);printf("\t* 阻塞的消费进程个数为:%d\n",num2);}void wakeup(int s){//唤醒函数的定义link p;link q=ready;if(s==1){ //唤醒b_s1队首进程,生产进程队列p=b_s1;b_s1=b_s1->next;//阻塞指针指向下一个阻塞进程strcpy(p->state,"Ready");strcpy(p->reason,"Null");while(q)//插入就绪队列q=q->next;q=p;p->next=NULL;printf("\t* p1生产进程唤醒了!\n");}else{ //唤醒b_s2队首进程,消费进程队列p=b_s2;b_s2=b_s2->next;//阻塞指针指向下一个阻塞进程strcpy(p->state,"Ready");strcpy(p->reason,"Null");while(q->next)//插入就绪队列q=q->next;q->next=p;p->next=NULL;printf("\t* c1消费进程唤醒了!\n");}}void control() //处理器调度程序{int rd;int num=0;link p=ready;if(ready==NULL) //若无就绪进程,结束return;while(p) //统计就绪进程个数{num++;p=p->next;//最终p变为NULL}printf("\t* 就绪进程个数为:%d\n",num);time_t t;srand((unsigned) time(&t));rd=rand()%num;//随机函数产生随机数if(rd==1){p=ready;ready=ready->next;ready->next=p;p->next=NULL;strcpy(ready->state,"Run");strcpy(ready->next->state,"Ready");}elsestrcpy(ready->state,"Run");pc=ready->breakp;}void processor(){ //模拟处理器指令执行if(strcmp(ready->name,"Producer")==0) //当前进程为生产者switch(pc){case 0://produceprintf("\t* 生产者生产了字符%c\n",str[sp]);rec_p[rp1]=str[sp];//添加到生产记录sp=(sp+1)%len;pc++;ready->breakp=pc; //保存断点break;case 1: //p(s1)pc++;p(1);break;case 2: //putbuffer[in]=rec_p[rp1]; //放到缓冲区printf("\t* %c字符成功入驻空缓存!\n",buffer[in]);rp1++;in=(in+1)%BUF;pc++;ready->breakp=pc; //保存断点break;case 3: //v(s2)pc++;printf("\t* 释放一个s2信号\n");v(2);break;case 4://goto01printf("\t* 生产进程goto 0 操作\n");pc=0;count--; //剩余字符个数减1printf("\t* 剩余字符count=%d个\n",count);ready->breakp=pc; //保存断点if(count<=0){ //生产结束printf("\t* 生产者结束生产!\n");strcpy(p1->state,"Stop");strcpy(p1->reason,"Null");ready->breakp=-1;ready=ready->next;//在就绪队列中去掉}}else //当前进程为消费者switch(pc){case 0: //p(s2)pc++;p(2);break;case 1: //getprintf("\t* 消费者取字符!\n");temp=buffer[out];out=(out+1)%BUF;pc++;ready->breakp=pc; //保存断点break;case 2: //v(s1)pc++;printf("\t* 释放一个s1\n");v(1);break;case 3: //consumeprintf("\t* 消费了字符%c\n",temp);rec_c[rp2]=temp;//添加到消费记录rp2++;con_cnt++;if(con_cnt>=len){strcpy(c1->state,"Stop");//完成态c1->breakp=-1;return;}pc++;ready->breakp=pc; //保存断点break;case 4: //goto0printf("\t* 消费进程goto 0 操作\n");pc=0;ready->breakp=pc; //保存断点}}void print(){int i,j;printf("--------生产者消费者模拟-------\n");printf("* 模拟过程的字符串为:\t");printf("%s\n",&str);printf("* 已生产:");for(j=0;j<=rp1;j++)printf("%c",rec_p[j]);printf("\n* 空缓存:");for(j=rp2;j<=rp1;j++)printf("%c",buffer[j]);printf("\n* 已消费:");for(j=0;j<=rp2;j++)printf("%c",rec_c[j]);printf("\n-------进程控制块的信息--------\n");printf("进程名\t\t状态\t等待原因\t断点\n");printf("%s\t%s\t%s\t\t%d\n\n",p1->name,p1->state,p1->reason, p1->breakp);printf("%s\t%s\t%s\t\t%d\n",c1->name,c1->state,c1->reason,c1 ->breakp);printf("-----------------------\n");printf("1.继续 0.退出\n");scanf("%d",&i);if(i==0){exit(0);}}主程序#include "a.h"#include "b.h"#include "c.h"void main(){printf("*生产者消费者模拟\n");printf("---------\n");printf("*请输入字符串:\n");scanf("%s",str); //string数组存放将要产生的字符len=strlen(str);count=len; //输入字符的个数init(); //初始化while(con_cnt<len) //消费完所有的字符为结束{system("cls"); //清屏操作printf("---------模拟指令流程--------\n");control(); //处理器调度程序processor(); //模拟处理器指令执行print(); //输出显示各个信息}printf("\n程序结束!\n"); }进程调度算法模拟进程管理是操作系统中的重要功能,用来创建进程、撤消进程、实现进程状态转换,它提供了在可运行的进程之间复用CPU的方法。