操作系统课程设计报告.docx
《操作系统课程设计报告.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计报告.docx(77页珍藏版)》请在冰豆网上搜索。
操作系统课程设计报告
操作系统课程设计报告
时间:
2013-12-2~2013-12-13
地点:
信息技术实验中心
软件工程专业
2011级2班26号
刘路峰
2013-12-13
1课程设计的目的和意义
一、课设目的
1.熟悉并巩固《操作系统》的基本概念和基本理论,加强对操作系统有关原理的理解;
2.培养学生自主学习、独立思考的能力,学会查找资料并善于分析资料的能力;
3.培养学生严谨的工作作风,提倡互相学习培养团队精神;
4.提高学生独立设计、独立调试程序的能力;
5.初步养成良好的系统软件分析和设计能力,形成良好的编程风格。
二、课设意义
本课程设计是学生在学完了《操作系统》课程后,培养学生程序设计能力的一个重要教学环节。
课程设计为学生提供了一个动手、动脑并独立实践的机会,有助于学生将教材的理论知识和实践相结合,从而锻炼学生分析问题、解决问题的能力,提高学生实际编写程序的能力,为学生学习计算机专业的后续课程打下良好基础。
本课程设计要求对操作系统的分析以加深对计算机硬件结构和系统软件的认识,初步掌握操作系统组成模块和应用接口的使用方法,提高进行工程设计和系统分析的能力,为毕业设计和以后的工程实践打下良好的基础。
2进程调度算法模拟
一、设计目的
通过进程的创建、撤销和运行加深对进程概念和今成年并发执行的理解,明确进程与程序的区别。
二、设计要求
1、了解系统调用fork()、exec()、exit()、waitpid()的功能及实现过程;
2、编写一段程序,使用系统调用fork()来创建两个子进程,并由父进程重复显示字符串“parent:
”和自己的标识数,而子进程则重复显示字符串“child:
”和自己的标识数;
3、编写一段程序,使用系统调用fork()来创建一个子进程,子进程通过调用exec()更换自己的执行代码,新的代码显示“newprogram.”后,调用exit()结束进程。
而父进程则调用waitpid()等待子进程结束,并在子进程结束后,显示子进程的标识符然后正常结束。
4、用C语言实现对N个进程采用动态优先权优先算法的进程调度:
(1)每个用来标识进程的进程控制块PCB用结构来描述,包括以下字段:
●进程标识符id
●进程优先数priority,并规定优先数越大的进程,其优先权越高;
●进程已占用的CPU时间cputime;
●进程还需占用的CPU时间alltime,当进程运行完毕时,alltime变为0;
●进程的阻塞时间startblock,表示当进程再运行startblock个时间片后,进程将进入阻塞状态;
●进程被阻塞的时间blocktime,表示已阻塞的进程再等待blocktime个时间片后,将转换成就绪态
●进程状态state;
●队列指针next,用来将PCB排成队列
(2)优先数改变的原则:
●进程在就绪队列中呆一个时间片,优先数增加1;
●进程每运行一个时间片,优先数减3。
(3)假设在调度前,系统中有5个进程,它们的初始状态如下:
ID
0
1
2
3
4
PRIORITY
9
38
30
29
0
CPUTIME
0
0
0
0
0
ALLTIME
3
3
6
3
4
STARTBLOCK
2
-1
-1
-1
-1
BLOCKTIME
3
0
0
0
0
STATE
READY
READY
READY
READY
READY
(4)为了清楚地观察诸进程的调度过程,程序应将每个时间片内的进程的情况显示出来,参照的具体格式如下:
RUNNINGPROG:
i
READY_QUEUE:
->id1->id2
BLOCK_QUEUE:
->id3->id4
==================================
ID01234
PRIORITYP0P1P2P3P4
CPUTIMEC0C1C2C3C4
ALLTIMEA0A1A2A3A4
STARTBLOCKT0T1T2T3T4
BLOCKTIMEB0B1B2B3B4
STATES0S1S2S3S4
三、算法思路
1、调用fork()函数创建一个进程,根据fork()函数的返回值判断创建的进程是子进程还是父进程,如果函数返回的值为0,说明创建的是子进程,调用getid()函数获取id并按照“Child1:
id”格式输出;若大于0,说明创建的是父进程,调用函数getid()获取id并按照“Parent:
id”格式输出。
由于fork函数被调用一次但返回两次,即在父进程中调用一次,在父进程和子进程中各返回一次,故如果创建的是父进程,还需再创建一个进程,若此时创建的是子进程,调用getid()函数获取id并按照“Child2:
id”格式输出即可。
2、调用fork()函数创建一个进程,根据fork()函数的返回值判断创建的进程是子进程还是父进程,如果函数返回的值为0,说明创建的是子进程,之后调用execl()函数更换执行代码,最后调用exit()函数结束;如果创建的是父进程,调用waitpid()函数等待子进程结束,使用一个int变量接收waitpid()函数返回的值,即子进程的标识符,最后输出即可。
3、首先,设置一个模拟操作系统的PCB数据结构的结构体,包括priority、cputime、alltime、startblock、blocktime、btime、state六个字段:
priority代表优先级,cputime代表运行时间,alltime代表剩余时间,startblock代表开始阻塞的时间,blocktime代表从阻塞到就绪所需时间,btime代表阻塞时的时间,state代表进程状态。
其中state有四个状态:
就绪(0),运行
(1),阻塞(-1),结束
(2)。
在进程执行过程中,先找出优先级priority最大的进程ID,如果有若干个进程的priority相同,则程序会选择还需时间ALLTIME最少的进程,此时更改当前执行的进程属性,如优先级priority、状态state、运行时间cputime、剩余时间alltime等,同时对处于就绪或阻塞状态的进程属性作相应更改,需要注意的是处于阻塞态的进程在阻塞了blocktime个时间后,状态应更改为就绪状态,可以根据当前系统时间(这里假设变量名为systime)与阻塞时的时间btime的差值(systime-btime)是否与从阻塞到就绪所需时间blocktime值相等来判断。
在当前进程执行结束或被阻塞后,需重新选择优先级priority最大的进程。
四、模块设计
1、头文件、结构体及全局变量
1#include
2#include
3#include
4#include
5#include
6structpcb{
7intid;//进程id
8intpriority;//优先级
9intcputime;//运行时间
10intalltime;//剩余时间
11intstartblock;//开始阻塞的时间
12intblocktime;//从阻塞到就绪所需时间
13intbtime;//阻塞时时间
14intstate;//进程状态
15}run[100];//pcb变量run
16intnum;//进程数
17intsystime;//系统时间
18intcur;//当前运行进程
2、主要函数
2.1Pro1()函数
传入参数:
无
传出参数:
无
主要功能:
创建两个子进程,父进程重复显示字符串“parent:
”和自己的标识数,而子进程则重复显示字符串“child:
”和自己的标识数。
1voidPro1()//第一个程序
2{
3intpid=fork();
4if(pid==0)printf("child:
%d\n",getpid());//第一个子进程
5elseif(pid>0)//生成的父进程
6{
7printf("parent:
%d\n",getpid());
8pid=fork();
9if(pid==0)printf("child:
%d\n",getpid());//第二个子进程
10}
11}
2.2Pro2()函数
传入参数:
无
传出参数:
无
主要功能:
创建一个子进程,子进程更换自己的执行代码,新的代码显示“newprogram.”后,结束进程。
而父进程则等待子进程结束,并在子进程结束后,显示子进程的标识符然后正常结束。
1voidPro2()//第二个程序
2{
3intstatus;
4intpid=fork();//创建一个进程
5if(pid==0)//如果为子进程
6{
7execl("/home/lfeng","ls",NULL);//更换代码
8printf("newprogram.\n");
9exit(0);//退出
10}
11elseif(pid>0)//如果为父进程
12{
13intnum=waitpid(pid,&status,0);//等待子进程
14printf("childid:
%d\n",num);//输出
15exit(0);//退出
16}
17}
2.3Read()函数
传入参数:
无
传出参数:
无
主要功能:
读取input.txt文件中预设定的数据,并进行处理
1voidRead()//读取文件
2{
3num=0;//初始化进程数为0
4FILE*rf;//file指针
5rf=fopen("input.txt","r");//打开文件
6if(rf==NULL)//失败
7{
8printf("failed\n");
9exit(0);
10}
11while(!
feof(rf))//除非不是文件结束符
12{
13fscanf(rf,"%d%d%d%d%d%d%d",&run[num].id,&run[num].priority,&run[num].cputime,&run[num].alltime,&run[num].startblock,&run[num].blocktime,&run[num].state);//获取数据
14run[num].btime=0;//初始化阻塞时时间为0
15num++;//进程数加1
16}
17fclose(rf);//关闭文件
18}
2.4FindMax()函数
传入参数:
无
传出参数:
进程序号maxi
主要功能:
寻找优先级最大的进程,如果有多个进程优先级相同,则比较进程的剩余时间alltime,此时返回alltime更小的进程,函数中使用变量maxpr记录找到的优先级最大的值,使用变量maxi记录找到的最大优先级对应的进程序号(注意不是进程的ID)。
首先,检查所有进程是否都为结束状态,如果是则返回-1,否则遍历整个进程队列,查找最符合要求的进程,最后返回进程的序号。
1intFindMax()//寻找优先级最大的进程
2{
3inti,maxpr=0,maxi=-1;//初始化
4for(i=0;i5if(run[i].state!
=2)break;//找到则跳出循环
6if(i==num)return-1;//如果没找到返回-1
7for(i=0;i8{
9if(run[i].state==2||run[i].state==-1)continue;
10//如果进程已结束或被阻塞,则跳过
11if(run[i].priority>maxpr||((run[i].priority==maxpr)
12&&(run[i].alltime13{
14maxi=i;//如果优先级比maxp更大,记录该进程
15maxpr=run[i].priority;
16}
17}
18returnmaxi;//返回进程序号
19}
2.5Run()函数
传入参数:
无
传出参数:
无
主要功能:
模拟进程的执行过程。
函数中,cur代表当前进程序号(非进程的id),status代表下一次执行的进程序号,systime代表系统时间,temp存储下一次执行的进程序号。
第一次执行时,调用FindMax()函数获取进程序号并用cur存储该值,随后根据status的值判断当前进程应做什么操作,初始status值为1,如果status值为1,则当前进程应执行运行操作(优先级priority-3,运行时间cputime+1,剩余时间alltime-1,状态state置为1,下同);如果status值为2,则当前进程应执行阻塞操作(状态state置为1,阻塞时的时间btime置为当前系统时间systime),同时调用FindMax()函数获取优先级最高的进程序号并执行运行操作;如果status值为3,则当前进程应执行结束操作,同时调用FindMax()函数获取优先级最高的进程序号并执行运行操作,如果当前进程剩余时间alltime值为0,则更改status值为3。
随后,调用FindMax()函数获取优先级最高的进程序号,判断此时获取的进程序号是否与当前执行的进程序号相同,若相同,且运行时间cputime等于阻塞时间startblock,则更改status值为2,否则默认为1;若不相同,则更改status值为2。
对于处于阻塞或就绪状态的进程,应修改对应的属性:
当前为就绪状态的进程优先级priority+1,当前为阻塞状态且满足转为就绪状态条件(阻塞时间达到blocktime)的进程状态更改为就绪状态。
循环以上执行过程,直至所有进程均处于结束状态。
主要过程如下:
1voidRun()//运行进程
2{
3systime=0;//初始化系统时间为0
4intstatus=1,temp;//初始化下一次状态为运行态(1代表运行态,2代表结束态,0代表就绪态,-1代表阻塞态)
5cur=FindMax();//找到优先级最大的进程并运行
6while(cur!
=-1)//除非没找到,cur为-1,否则执行while循环
7{
8systime++;//系统时间加1
9if(status==2)//如果为阻塞态
10{
11run[cur].state=-1;//改变当前进程状态为阻塞态
12run[cur].btime=systime;//记录当前时间
13cur=FindMax();//找到优先级最大的进程并运行
14}
15elseif(status==3)//ifend
16{
17run[cur].state=2;//改变当前进程状态为结束态
18run[cur].priority=0;
19//优先级设置为0,避免影响进程的选择
20cur=FindMax();//找到优先级最大的进程并运行
21}
22run[cur].state=1;//改变进程状态为运行态
23run[cur].alltime--;//剩余时间减1
24run[cur].cputime++;//运行时间加1
25run[cur].priority-=3;//优先级减3
26temp=FindMax();
27//由于进程优先级发生变化,故需再找优先级最大的进程
28if(run[cur].alltime==0)
29status=3;//alltime为0,改为结束态
30elseif(temp==cur)
31{//如果找到的进程是当前进程,根据情况判断下一次进程状态
32if(run[cur].cputime==run[cur].startblock)
33status=2;//运行时间等于阻塞时间,改变为阻塞态
34elsestatus=1;//否则为运行态
35}
36elsestatus=2;//否则为阻塞态
37for(inti=0;i38{
39if(run[i].state==-1&&
40(systime-run[i].btime==run[i].blocktime))
41run[i].state=0;//达到阻塞时间,改变为就绪态
42elseif(run[i].state==0)
43run[i].priority+=1;//如果为就绪态,优先级加1
44}
45printf("RUNNINGPROG:
%d\n",cur);
46intflag=0;//标记是否有进程被阻塞或就绪
47printf("READY_QUEUE:
");
48for(inti=0;i49if(run[i].state==0){printf("->%d",i);flag=1;}
50//如果为就绪态,输出,并设置标记为1
51if(flag==0)printf("NULL");
52flag=0;
53printf("\nBLOCK_QUEUE:
");
54for(inti=0;i55if(run[i].state==-1){printf("->%d",i);flag=1;}
56//如果为阻塞态,输出,并设置标记为1
57if(flag==0)printf("NULL");
58printf("\n");
59Output();//输出所有进程信息
60}
61}
3、流程图
五、程序代码
(由于代码较多,前面所列函数的代码不贴出)
1#include
2#include
3#include
4#include
5#include
6structpcb{
7intid;//进程id
8intpriority;//优先级
9intcputime;//运行时间
10intalltime;//剩余时间
11intstartblock;//开始阻塞的时间
12intblocktime;//从阻塞到就绪所需时间
13intbtime;//阻塞时时间
14intstate;//进程状态
15}run[100];//pcb变量run
16intnum;//进程数
17intsystime;//系统时间
18intcur;//当前运行进程
19voidOutputStatus(intstatus)//输出状态
20{
21switch(status)
22{
23case0:
printf("ready\n");break;//0为就绪
24case1:
printf("run\n");break;//1为运行
25case2:
printf("end\n");break;//2为结束
26case-1:
printf("block\n");break;//-1为阻塞
27}
28}
29voidOutput()//输出进程信息
30{
31printf("IDPRIOTRITYCPUTIMEALLTIMESTARTBLOCKBLOCKTIMESTATE\n");//项目
32for(inti=0;i33{
34printf("%d%6d%4d%4d%6d%5d",run[i].id,run[i].priority,run[i].cputime,run[i].alltime,run[i].startblock,run[i].blocktime);//进程各项信息
35OutputStatus(run[i].state);//输出进程状态
36}
37}
38intmain()//主函数
39{
40intchoice=-1;//定义选择变量choice,接收用户选择
41while(choice<1||choice>3)
42{
43printf("可执行的操作:
\n1.调用fork()创建两个子进程,并由父进程重复显示字符串\n2.调用fork()创建一个子进程,子进程通过调用exec()更换自己的执行代码\n3.N个进程采用动态优先权优先算法的进程调度\n请选择要执行的操作:
");
44scanf("%d",&choice);
45}
46switch(choice)
47{
48case1:
Pro1();break;
49case2:
Pro2();break;
50case3:
51Read();//读取文件
52Run();//运行进程
53break;
54}
55return0;
56}
六、运行结果
(数据较多,不一一贴出)
由于每次记录的状态是从当前这一秒开始时的状态,故执行完全部进程总共用时19s。
3动态分区分配方式模拟
一、设计目的
了解动态分区分配方式中使用的数据结构和分配算法,并进一步加深对动态分区存储管理方式及其实现过程的理解。
二、设计要求
1、用C语言分别实现采用首次适应算法和最佳适应算法的动态分区分配过程alloc()和回收过程free().其中空闲分区通过空闲分区链来管理;在进行内存分配时,系统优先使用低端的空间。
2、假设初始状态下可用的内存空间为640K,并有下列的请求序列:
作业1申请130KB空间
作业2申请60KB空间
作业3申请100KB空间
作业2释放60KB空间
作业4申请200KB空间
作业3释放100KB空间
作业1释放130KB空间
作业5申请140KB空间
作业6申请60KB空间
作业7申请50KB空间
作业6释放60KB空间
分别采用首次适应和最佳适应算法进行内存块的分配和回收,要求每次分配和回收后显示出空闲区内存分区链的情况。
三、算法思路
首次适应算法(First-Fit):
当作业申请分配内存空间时,先查链表,在各空闲区中查找满足大小要求的可用块。
只要找到第一个足以满足要求的空闲块就停止查找,并将它分配给作业:
如果该空闲空间与所需空间大小相等,则更改该空间状态并设置对应的作业号即可;如果大于所需空间大小,则从该分区中划出对应的内存空间分配给