操作系统实验报告(读者写着问题,时间片轮转算法,内存的分配,进程的调度)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
电子科技大学计算机学院实验中心
小心
计算机专业类课程
实验报告
课程名称:操作系统
学 院:软件学院
专 业:软件工程
学生姓名:李 希
学 号:2010231020018
指导教师:丁老师
日 期: 2012年5月5日
电子科技大学
实验报告
实验一
一、实验名称:进程管理
二、实验学时:4
三、实验内容和目的:
实验内容:
(1)进程的创建
写一段源程序,创建两个进程,当此程序运行时,在系统中有一个父进程和两个子进程活动。
让每一个进程在屏幕上显示字符。
观察纪录屏幕上的显示结果,然后分析原因。
(2)进程的控制
修改编写的程序,将每个进程输出一个字符改为每个进程输出一句话,在观察程序执行时屏幕出现的现象,并分析原因。
实验目的:
(1)加深对进程概念的理解,明确进程和程序的区别。
(2)进一步认识并发执行的实质。
(3)分析进程竞争资源现象,学习解决进程互斥的方法。
四、实验原理:
利用fork函数来创建子进程,并返回子进程的ID号。
利用lockf函数来实现信号量对进程的资源竞争的调度,和互斥的方法。
五、实验器材(设备、元器件):
一台装有VS2010的电脑,操作系统为WIN7.
六、实验步骤:
(1)先写好2个子进程程序,并且让2个子程序在屏幕上分别打印出A,B
(2)父进程创建2个子进程,并在屏幕上打印出C。
(3)观察进程竞争资源的现象。
七、实验数据及结果分析:
电子科技大学计算机学院实验中心
子进程A的代码:
#include<iostream>
#include<windows.h>
using namespace std;
int main()
{
cout<<"I'm Process A/n"<<endl;
return 0;
}
子进程B的代码:
#include<iostream>
using namespace std;
int main()
{
cout<<"I'm Process B"<<endl;;
return 0;
}
父进程C的代码:
//#include "stdafx.h"
#include<windows.h>
#include<iostream>
using namespace std;
void print_error()
{
DWORD nErrorNo = GetLastError ( );
LPSTR lpBuffer;
FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
nErrorNo,
LANG_NEUTRAL,
(LPTSTR) & lpBuffer,
0 ,
NULL );
if (lpBuffer == NULL)
{
lpBuffer = "Sorry, cannot find this error info. ";
}
printf("%s (%d).\n", lpBuffer, nErrorNo);
}
int fork(const char* pszApplication,HANDLE& hProcess)
{
STARTUPINFO si={sizeof(si)};
PROCESS_INFORMATION pi;
if(!CreateProcess(pszApplication,NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)) return -1;
else
{
hProcess=pi.hProcess;
return pi.dwProcessId;
}
}
void lockf(HANDLE hObj)
{
DWORD state = WaitForSingleObject(hObj,INFINITE);
switch (state)
{
case WAIT_OBJECT_0:
printf("\nProcess exit.\n");
break;
case WAIT_TIMEOUT:
printf("\nTime out.\n");
break;
case WAIT_FAILED:
printf("\nWait Failed.\n");
print_error();
break;
}
}
int main(int argc, char* argv[])
{
HANDLE hProcess1,hProcess2;
int child1=fork("C:\\操¨´作Á¡Â系¦Ì统ª3实º¦Ì验¨¦\\ProcessA\\Debug\\ProcessA.exe",hProcess1);
if(-1==child1)
{
cout << "fork error!\n";
return -1;
}
lockf(hProcess1);
电子科技大学计算机学院实验中心
int child2=fork("C:\\操¨´作Á¡Â系¦Ì统ª3实º¦Ì验¨¦\\ProcessB\\Debug\\ProcessB.exe",hProcess2);
if(-1==child2)
{
cout << "fork error!\n";
return -1;
}
cout<<"This is Process C\n";
lockf(hProcess2);
return 0;
}
程序运行的结果:
八、实验结论、心得体会和改进建议:
实验结论:成功的通过了父进程C来创建了2个子进程A,B,并成功的对子进
程进行了调度与管理。
心得体会:通过对进程的创建,调度,更加深了我们对操作系统这门课的进程的了解,而且也锻炼了我们写代码的能力,和解决问题的能力。
改进建议:对于我们大二没有接触过Windows编程的学生来说,可能一些Windows的API函数不够了解,以至于比较难理解老师给出的参考代码。
所以我希望,老师以后可以先给我们大家简单的讲解,介绍一下比较实用的Windows编程的API的函数。
实验二
一、实验名称:处理器调度
二、实验学时:4
三、实验内容和目的:
实验内容:
(1)假定系统有五个进程,每一个进程用一个进程控制块PCB来代表。
电子科技大学计算机学院实验中心
PCB的格式为:
其中,进程名——作为进程的标识,假设五个进程的进程名分别为1,2,3,4,5指针——进程按顺序排成循环队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程的指针指出第一个进程的进程控制块首地址。
要求运行时间——假设进程需要运行的单位时间数。
已运行时间——假设进程已经运行的单位时间数,初始值为“0”。
状态——有两种状态,“ready”和“end”,初始状态都为“ready”,用“ready”表示。
当一个进程运行结束后,它的状态为“end”,用“end”表示。
(2) 每次运行所设计的处理器调度程序前,为每个进程任意确定它的“要求运行时间”。
(3) 把五个进程按顺序排成循环队列,用指针指出队列连接情况。
另用一标志单元记录轮到运行的进程。
例如,当前轮到2执行,则有:
(4) 处理器调度总是选择标志单元指示的进程运行。
由于本实验是模拟处理器调度的功能,对被选中的进程并不实际的启动运行,而是执行:已运行时间+1来模拟进程的一次运行,表示进程运行过一个单位的时间。
(5) 进程运行一次后,把该进程的进程控制块中的指针值送到标志单元,指示下一个轮到运行的进程。
同时应判断该进程的要求运行时间与已运行时间,若该进程的要求运行时间 已运行时间,则表示它尚未执行结束,应待到下一轮时再运行。
若该进程的要求运行时间等于已运行时间,则表示它已经执行结束,应把它的状态修改成“结束”(end)且退出队列。
此时,应把该进程的进程控制块中的指针值送到前面一个进程的指针位置。
(6) 若“ready”状态的进程队列不为空,则重复上面的(4)和(5)
电子科技大学计算机学院实验中心
的步骤,直到所有的进程都成为“ready”状态。
(7) 在所设计的程序中应有显示或打印语句,能显示或打印每次选中进程的进程名以及运行一次后进程队列的变化。
(8) 为N个进程任意确定一组“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中的进程名以及进程控制块的动态变化过程。
实验目的:
在用多道程序设计的系统中,往往有若干个进程同时处于就绪状态。
所以当就绪进程个数大于处理器数时,就必须依照某种策略来决定哪些进程优先占用CPU。
本实验模拟在单处理器情况下的处理器调度,加深了解处理器调度的工作。
四、实验原理:
定义进程PCB结构体。
并用采用C++中的指针形成循环链表,并对链表中的结构进行操作。
来模仿时间片轮转的进程调度。
五、实验器材(设备、元器件):
一台装有VS2010的电脑,操作系统为WIN7.
六、实验步骤:
(1)定义结构体PCB:里面有进程的编号,执行需要的时间,和已经运行时间,还有进程的状态信息。
(2)定义循环的单链表,来使结构都串联起来。
(3)使用时间片轮转的方法来动态地进行进程模拟的调度。
(4)如果所有的进程都执行完毕,则退出程序。
七、实验数据及结果分析:
实验程序的代码如下:
#include<iostream>
#include<string>
using namespace std;
struct Process{
int Name;
string Statu;
int NeedTime;
int RunTime;
Process *Next;
};
struct Process *CreateList(int n)//初始化链表,并返回指向链表头的指针
{
struct Process *head=NULL,*tail=NULL;
for(int i=1;i<=n;i++)
{
if(i==1)
{
head=new Process;
tail=head;
head->Name=i;
head->RunTime=0;
电子科技大学计算机学院实验中心
head->Statu="Ready";
cout<<"请输入"<<i<<"号进程运行所需要的时间";
cin>>tail->NeedTime;
}
if(i!=1&&i!=n)
{
tail->Next=new Process;
tail=tail->Next;
tail->Name=i;
tail->RunTime=0;
tail->Statu="Ready";
cout<<"请输入¨²"<<i<<"号进程运行所需要的时间";
cin>>tail->NeedTime;
}
if(i==n)
{
tail->Next=new Process;
tail=tail->Next;
tail->Next=head;
tail->Name=i;
tail->RunTime=0;
tail->Statu="Ready";
cout<<"请输入¨²"<<i<<"进程所需要运行的时间";
cin>>tail->NeedTime;
tail=head;
}
}
return tail;
}
void Run(struct Process *tail,int ProcessNum)//时间片轮转
{
while(ProcessNum!=0)
{
if((tail->RunTime!=tail->NeedTime))
{
tail->RunTime++;
cout<<"进程"<<tail->Name<<" 正在运行\n";
cout<<"需要运行时间"<<tail->NeedTime<<"\n";
cout<<"已经运行时间"<<tail->RunTime<<"\n";
cout<<"进程的状态"<<tail->Statu<<"\n";
cout<<"******************************"<<"\n";
cout<<"******************************"<<"\n";
cout<<"******************************"<<"\n";
if(tail->RunTime==tail->NeedTime)
{
if(tail->Statu=="Ready")
{
ProcessNum--;
tail->Statu="End";
}
}
tail=tail->Next;
}
else
{
tail=tail->Next;
}
}
}
int main()
{
struct Process * runtail;
runtail=NULL;
int n;
int ProcessNum;
cout<<"请输入进程的个数";
cin>>n;
ProcessNum=n;
runtail=CreateList(n);
Run(runtail,ProcessNum);
getchar();
getchar();
}
实验结果:
电子科技大学计算机学院实验中心
八、实验结论、心得体会和改进建议:
实验结论:成功的采用链表的形式,用指针,模仿了时间片轮转算法,完成了实验的要求,达到了实验的目的。
心得体会:通过本次实验加深了我们对时间轮转算法的印象,并且锻炼了我们的动手能力,还温习了一下C++中一些编程的知识。
改进建议:我觉得时间片算法可能过于简单了,其实我们可以在时间片算法的基础上再增加一些功能,比如在时间片算法上增加优先级这个属性,这样不仅加大了实验的难度,还可以让同学们对优先级调度有一种更直观,更深刻的了解。
实验三
一、实验名称:主存储器空间的分配与回收
二、实验学时:4
三、实验内容和目的:
实验内容:
电子科技大学计算机学院实验中心
分页式管理方式采用位示图来表示主存分配情况,实现主存空间的分配和回收。
实验目的:
一个好的计算机系统不仅要有一个足够容量的、存取速度高的、稳定可靠的主存储器,而且要能合理地分配和使用这些存储空间。
当用户提出申请存储器空间时,存储管理必须根据申请者的要求,按一定的策略分析主存空间的情况,找出足够的空闲区域分配给申请者。
当作业撤离或主动归还主存资源时,则存储管理要收回作业占用的主存空间或归还部分主存空间。
主存的分配和回收的实现虽与主存储器的管理方式有关的。
通过本实验帮助学生理解在不同的存储管理方式下应怎样实现主存空间的回收和分配。
四、实验原理:
(1)分页式存储器把主存分成大小相等的若干块,作业的信息也按块的大
小分页,作业装入主存时可把作业的信息按页分散存放在主存的空闲
块中,为了说明主存中哪些块已经被占用,哪些块是尚未分配的空闲
块,可用一张位示图来指出。
位示图可由若干存储单元来构成,其中
每一位与一个物理块对应,用0/1表示对应块为空闲/已占用。
(2)设某系统主存被分成大小相等的64块,则位示图可用8*8个字节来构
成,另用一单元记录当前空闲块数。
若已有第0,1,4,5,6,9,11,13,24,31,共10个主存块被占用了,那么位示图情况如下:
(3)当装入一个作业时,根据作业对主存的需要量,先查当前空闲块数是
否能满足作业要求,若不能满足则输出分配不成功。
若能满足,则查
位示图,找出为“0”的一些位,置上占用标志“1”,并且从“当前
空闲块数”中减去本次任务占用块数。
然后按找到的计算出对应的块号:
其计算公式为:块号= j*8+i
其中,j表示找到的是第n个字节,i表示对应的是第n位。
根据分配给作业的块号,为作业建立一张页表,页表格式:
(4) 当作业执行结束,归还主存时,根据该作业的页表可以知道应归还的块号。
电子科技大学计算机学院实验中心
由块号可计算出在位示图中的对应位置,把对应位的占用标志清成“0”,表示对应的块已成为空闲块。
归还的块数加入到当前空闲块数中。
由块号计算在位示图中的位置的公式如下:
字节号 j=[块号/8] ([ ]表示取整)
位数 i={块号/8} ({ }表示取余)
(5) 设计实现主存分配和回收的程序。
假定位示图的初始状态如(2)所述,现
有一信息量为N页的作业要装入,运行你所设计的分配程序,为作业分配主存且建立页表(格式如(3)所述)。
五、实验器材(设备、元器件):
一台装有VS2010的电脑,操作系统为WIN7.
六、实验步骤:
(1)先创建一个8*8的数组,用来保存内存的信息。
并初始化好值,用1来表示
已经分配,用0来表示还没有分配。
(2)创建一个Sum函数,来对内存中没有分配的内存个数进行统计,并返回一
个int类型的数值,来表示没有分配的内存的大小、
(3)创建一个分配内存的函数,先判断需求的内存的大小是否小于内存空闲的大
小。
如果能够满足要求,则将相应的内存空间修改为1,表示已经分配。
(4)创建一个打印内存页表的函数,根据内存的实际情况,如果为1,则打印输
出,最后在屏幕上打印出所有的空闲页表。
(5)创建主函数,并对相应的函数进行调用,便可成功的模仿内存的调度。
七、实验数据及结果分析:
具体的代码如下:
#include<iostream>
using namespace std;
void Print(int Table[8][8])//显示内存
{
cout<<"分配内存后最新的内存情况如下表"<<endl;
cout<<" "<<0<<" "<<1<<" "<<2<<" "<<3<<" "<<4<<" "<<5<<" "<<6<<" "<<7<<"\n";
for(int j=0;j<8;j++)
{
cout<<j;
for(int k=0;k<8;k++)
{
cout<<" "<<Table[j][k];
}
cout<<"\n";
}
}
int Sum(int Table[8][8])//计算内存的剩余量
{
int n=0;
for(int j=0;j<8;j++)
{
电子科技大学计算机学院实验中心
for(int k=0;k<8;k++)
{
if(Table[j][k]==0)
{
n++;
}
}
}
return n;
}
void Manage(int Table [8][8],int Need)//分配内存
{
while(Need!=0)
{
for(int j=0;j<8;j++)
{
for(int k=0;k<8;k++)
{
if(Table [j][k]==0&&Need!=0)
{
Table [j][k]=1;
Need--;
}
}
}
}
}
void YeBiao(int Table [8][8])//打印空闲页表
{
cout<<"分配后空闲内存的页表"<<endl;
cout<<"页号"<<" "<<"块号"<<endl;
int i=1;
int h;
for(int j=0;j<8;j++)
{
for(int k=0;k<8;k++)
{
if(Table [j][k]==0)
{
h=8*j+k;
cout<<i<<" "<<h<<endl;
i++;
}
}
}
}
int main()
{
int Table[8][8];
int Va,Need;
for(int i=0;i<8;i++)//初始化页表
{
for(int k=0;k<8;k++)
{
Table[i][k]=0;
}
}
Table[0][0]=1;
Table[0][1]=1;
Table[0][4]=1;
Table[0][5]=1;
Table[0][6]=1;
Table[1][1]=1;
Table[1][3]=1;
Table[1][5]=1;
Table[3][0]=1;
Table[3][7]=1;
Print(Table);
Va=Sum(Table);
cout<<"\n"<<"现在有"<<Va<<"个块可用"<<"\n";
cout<<"请输入你要分配的块数";
cin>>Need;
while(Need>Va)
{
cout<<"对不起没有足够内存,请重新输入\n";
cin>>Need;
}
Manage(Table,Need);
Print(Table);
电子科技大学计算机学院实验中心
YeBiao(Table);
getchar();
getchar();
}
(1)若申请的内存数过大。
(2)申请的内存为45:
八、实验结论、心得体会和改进建议:
实验结论:达到了实验的要求与目的,完成了对内存分配的模拟。
心得体会:通过本次实验,我加深了采用页表的方式来管理内存的印象,锻炼了自己C++的编程能力,和独立解决问题的能力。
改进建议:实验中并没有要求对内存空间清理,删除的功能,我希望老师能加上对内存紧凑,清理,删除这些功能的模拟,这样可以使我们所学的知识更有用武之地。
电子科技大学计算机学院实验中心
实验四
一、实验名称:读者写者问题
二、实验学时:4
三、实验内容和目的:
实验内容:
可用于解决多个进程共享一个数据区(文件、内存区、一组寄存器等),其中若干读进程只能读数据,若干写进程只能写数据等实际问题
读者和写者应满足的条件:
(1)允许多个读者可以同时读文件
(2)不允许多个写者同时写文件,只能互斥写文件
(3)当写进程在写时不能读
(4)读者优先: 指一旦有读者正在读数据,允许多个读者同时进入读数据,只有当全部读者退出,才允许写者进入写数据。
(5)写者优先:指只要有一个写者申请写数据,则不再允许新的读者进入读数据
实验目的:
通过本实验对读者写者的模拟,让我们对操作系统中读者写着问题的解决有一个加深的影响,并学会使用一些模拟简单的信号量的方法,来解决一些比较经典的读者写着的问题。
四、实验原理:
(1)为了模拟读者写着的问题,因为自己的C++技术不够深厚,于是用Java 中的线程来进行模拟、采用输入输出流来对文本文件Test.txt进行操作。
(2)要实现写着互斥的写文件,这里只需要将线程中的Run方法定义为synchronized,就可以实现写着互斥的写文件、
(3)引入一个couter类,并对counter类中的成员进行维护,若有读者读数据,则对counter内的reader++,写者同理。
(4)读者写着不同的优先级,可以通过依赖counter类来实现。
在进行文件读写操作时,先判断是否有读者/写者。
五、实验器材(设备、元器件):
一台装有eclipse,和Win7的个人PC。
六、实验步骤:
电子科技大学计算机学院实验中心
(1)定义读者,写者类并继承Thread类,在其中的Run方法中调用输入输出流
来,读写文件
(2)创建counter类,来对读者,写者进行计数。
(3)在主函数中创建读者写者,并调用相应的Run方法,并观察实验的结果。
七、实验数据及结果分析:
实验的具体代码:
import java.util.Scanner;
public class ReadAndWrite {
public static void main(String []arg)
{
Scanner in= new Scanner(System.in);
System.out.println("请选择模拟的情况:1为读者优先。
2为写者优先");
int Situation;
Situation = in.nextInt();
if(Situation==2)//写者优先
{
Writer w1=new Writer(1);
w1.start();
Reader r2=new Reader(2);
r2.start();
Writer w2=new Writer(2);
w2.start();
}
else//读者优先
{
Reader1 r1=new Reader1(1);
r1.start();
Reader1 r2=new Reader1(2);
r2.start();
Writer1 w2=new Writer1(2);
w2.start();
}
}
}
class Counter
{
static int WriterCounter=0;
static int ReaderCounter=0;
}
class Writer extends Thread//写者优先
{
int WriteNum;
Writer(int WriteNum)
{
this.WriteNum=WriteNum;
}
synchronized public void run()
{
Counter.WriterCounter++;
System.out.println("now Writer"+" "+WriteNum+" "+"is Writing");
for(int i=0;i<10;i++){
System.out.println("********************************");
}
Counter.WriterCounter--;
}
}
class Writer1 extends Thread
{
int WriteNum;
Writer1(int WriteNum)
{
this.WriteNum=WriteNum;
}
synchronized public void run()
{
if(Counter.ReaderCounter==0)
{
Counter.WriterCounter++;
System.out.println("now Writer"+" "+WriteNum+" "+"is Writing");
for(int i=0;i<10;i++){
System.out.println("********************************");
}
电子科技大学计算机学院实验中心
Counter.WriterCounter--;
}
else
{
System.out.println("Now File is Reading,Writer can't Write");
try{
sleep(1000);
}catch(Exception ex)
{
ex.printStackTrace();
}
System.out.println("********************************");
System.out.println("Writer is Writing");
}
}
}
class Reader extends Thread
{
int ReadNum;
Reader(int ReadNum)
{
this.ReadNum=ReadNum;
}
public void run()
{
if(Counter.WriterCounter==0)
{
Counter.ReaderCounter++;
System.out.println("now Reader"+" "+ReadNum+" "+"is Reading");
for(int i=0;i<10;i++){
System.out.println("********************************");
}
Counter.ReaderCounter--;
}
else
{
System.out.println("now File is Writing,Reader can't Read");
try{
sleep(1000);
}catch(Exception ex)
{
ex.printStackTrace();
}
System.out.println("********************************");
System.out.println("Reader is Reading");
}
}
}
class Reader1 extends Thread//读者优先
{
int ReadNum;
Reader1(int ReadNum)
{
this.ReadNum=ReadNum;
}
public void run()
{
Counter.ReaderCounter++;
System.out.println("now Reader"+" "+ReadNum+" "+"is Reading");
for(int i=0;i<10;i++){
System.out.println("********************************");
}
Counter.ReaderCounter--;
}
}
实验的结果:
(1)
读者优先:
电子科技大学计算机学院实验中心
(2)写者优先:
八、实验结论、心得体会和改进建议:
实验结论:基本完成了实验的要求,实现了对经典的读者写着问题的解决。
心得体会:通过本次实验,加深了我对读者写着问题的理解,学会了用软件模拟的办法来实现一些简单的信号量对读者写者的控制,并且锻炼了自己Java 编程的能力,和独立解决问题的能力
改进建议:实际上,对于读者写者的问题,我们有多种解决办法,在这里我们只是模拟了一下软件编程的方法,还有一些方法,比如信号量,中断屏蔽等方法,还没有模拟,所以希望在以后的实验中可以增加一些对这些方法的模拟,以加深我们对读者写者问题的理解。