操作系统课程设计报告Word下载.docx
《操作系统课程设计报告Word下载.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计报告Word下载.docx(77页珍藏版)》请在冰豆网上搜索。
ID
1
2
3
4
PRIORITY
9
38
30
29
CPUTIME
ALLTIME
6
STARTBLOCK
-1
BLOCKTIME
STATE
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<
unistd.h>
2#include<
stdio.h>
3#include<
sys/types.h>
4#include<
sys/wait.h>
5#include<
stdlib.h>
6structpcb{
7intid;
//进程id
8intpriority;
//优先级
9intcputime;
//运行时间
10intalltime;
//剩余时间
11intstartblock;
//开始阻塞的时间
12intblocktime;
//从阻塞到就绪所需时间
13intbtime;
//阻塞时时间
14intstate;
//进程状态
15}run[100];
//pcb变量run
16intnum;
//进程数
17intsystime;
//系统时间
18intcur;
//当前运行进程
2、主要函数
2.1Pro1()函数
传入参数:
无
传出参数:
主要功能:
创建两个子进程,父进程重复显示字符串“parent:
”和自己的标识数。
1voidPro1()//第一个程序
2{
3intpid=fork();
4if(pid==0)printf("
child:
%d\n"
getpid());
//第一个子进程
5elseif(pid>
0)//生成的父进程
6{
7printf("
parent:
8pid=fork();
9if(pid==0)printf("
//第二个子进程
10}
11}
2.2Pro2()函数
创建一个子进程,子进程更换自己的执行代码,新的代码显示“newprogram.”后,结束进程。
而父进程则等待子进程结束,并在子进程结束后,显示子进程的标识符然后正常结束。
1voidPro2()//第二个程序
3intstatus;
4intpid=fork();
//创建一个进程
5if(pid==0)//如果为子进程
7execl("
/home/lfeng"
"
ls"
NULL);
//更换代码
8printf("
newprogram.\n"
);
9exit(0);
//退出
11elseif(pid>
0)//如果为父进程
12{
13intnum=waitpid(pid,&
status,0);
//等待子进程
14printf("
childid:
num);
//输出
15exit(0);
16}
17}
2.3Read()函数
读取input.txt文件中预设定的数据,并进行处理
1voidRead()//读取文件
3num=0;
//初始化进程数为0
4FILE*rf;
//file指针
5rf=fopen("
input.txt"
r"
//打开文件
6if(rf==NULL)//失败
7{
failed\n"
11while(!
feof(rf))//除非不是文件结束符
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
17fclose(rf);
//关闭文件
18}
2.4FindMax()函数
进程序号maxi
寻找优先级最大的进程,如果有多个进程优先级相同,则比较进程的剩余时间alltime,此时返回alltime更小的进程,函数中使用变量maxpr记录找到的优先级最大的值,使用变量maxi记录找到的最大优先级对应的进程序号(注意不是进程的ID)。
首先,检查所有进程是否都为结束状态,如果是则返回-1,否则遍历整个进程队列,查找最符合要求的进程,最后返回进程的序号。
1intFindMax()//寻找优先级最大的进程
3inti,maxpr=0,maxi=-1;
//初始化
4for(i=0;
i<
num;
i++)//寻找是否存在没有结束的进程
5if(run[i].state!
=2)break;
//找到则跳出循环
6if(i==num)return-1;
//如果没找到返回-1
7for(i=0;
i++)//寻找优先级最大的进程
8{
9if(run[i].state==2||run[i].state==-1)continue;
10//如果进程已结束或被阻塞,则跳过
11if(run[i].priority>
maxpr||((run[i].priority==maxpr)
12&
&
(run[i].alltime<
run[maxi].alltime)))
13{
14maxi=i;
//如果优先级比maxp更大,记录该进程
15maxpr=run[i].priority;
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()//运行进程
3systime=0;
//初始化系统时间为0
4intstatus=1,temp;
//初始化下一次状态为运行态(1代表运行态,2代表结束态,0代表就绪态,-1代表阻塞态)
5cur=FindMax();
//找到优先级最大的进程并运行
6while(cur!
=-1)//除非没找到,cur为-1,否则执行while循环
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;
i++)//检查阻塞态进程是否达到阻塞时间
38{
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:
cur);
46intflag=0;
//标记是否有进程被阻塞或就绪
47printf("
"
48for(inti=0;
i++)
49if(run[i].state==0){printf("
%d"
i);
flag=1;
}
50//如果为就绪态,输出,并设置标记为1
51if(flag==0)printf("
NULL"
52flag=0;
53printf("
\nBLOCK_QUEUE:
54for(inti=0;
55if(run[i].state==-1){printf("
56//如果为阻塞态,输出,并设置标记为1
57if(flag==0)printf("
58printf("
\n"
59Output();
//输出所有进程信息
60}
61}
3、流程图
五、程序代码
(由于代码较多,前面所列函数的代码不贴出)
19voidOutputStatus(intstatus)//输出状态
20{
21switch(status)
22{
23case0:
printf("
ready\n"
break;
//0为就绪
24case1:
run\n"
//1为运行
25case2:
end\n"
//2为结束
26case-1:
block\n"
//-1为阻塞
27}
28}
29voidOutput()//输出进程信息
30{
31printf("
IDPRIOTRITYCPUTIMEALLTIMESTARTBLOCKBLOCKTIMESTATE\n"
//项目
32for(inti=0;
i++)//循环输出
33{
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("
choice);
45}
46switch(choice)
47{
48case1:
Pro1();
49case2:
Pro2();
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):
当作业申请分配内存空间时,先查链表,在各空闲区中查找满足大小要求的可用块。
只要找到第一个足以满足要求的空闲块就停止查找,并将它分配给作业:
如果该空闲空间与所需空间大小相等,则更改该空间状态并设置对应的作业号即可;
如果大于所需空间大小,则从该分区中划出对应的内存空间分配给