Linux操作系统课程设计—时间片法和优先数法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《操作系统原理》课程设计报告
二〇一一年十二月十二日
目录
一、《操作系统原理》课程设计的目的与要求 (3)
1、目的 (3)
2、要求 (3)
二、简述课程设计内容、主要功能和实现环境 (3)
1.课程设计内容 (3)
三、任务的分析、设计、实现和讨论 (3)
1、任务的分析 (3)
2、任务的设计与实现 (4)
五、附录 (12)
进程调度—优先数法与简单轮转法
一、《操作系统原理》课程设计的目的与要求
1、目的
进程是操作系统最重要的概念之一,进程调度又是操作系统核心的主要内容。
本实习要求学生独立地用高级语言编写和调试一个简单的进程调度程序。
调度算法可任意选择或自行设计。
任务一采用简单轮转法,任务二采用优先数法等。
本课题可以加深对进程调度和各种调度算法的理解。
2、要求
(1)设计一个有n个进程并发的进程调度程序。
每个进程由一个进程控制块(PCB)表示。
进程控制块一般应该包含下述信息:进程名、进程优先数、进程需要运行的时间、占用CPU 的时间以及进程的状态等,且可按调度算法的不同而增删。
(2)调度程序应包含2种不同的调度算法,运行时可任意选一种,以利于各种算法的分析比较。
(3)算法应能显示或打印各个进程的PID、状态(运行状态R、等待状态W等)和参数(已运行时间等)的变化情况,便于观察诸进程的调度过程
进程是操作系统最重要的概念之一,进程调度又是操作系统核心的主要内容。
本实习要求学生独立地用高级语言编写和调试一个简单的进程调度程序。
调度算法可任意选择或自行设计。
任务一采用简单轮转法,任务二采用优先数法等。
本课题可以加深对进程调度和各种调度算法的理解。
二、简述课程设计内容、主要功能和实现环境
1.课程设计内容
进程调度是处理机管理的核心内容。
本实验要求用C语言编写和调试一个简单的进程调度程序。
选用优先数法或简单轮转法对五个进程进行调度。
每个进程处于运行R(run)、就绪W(wait)和完成F(finish)三种状态之一,并假设起始状态都是就绪状态W。
为了便于处理,程序进程的运行时间以时间片为单位计算。
各进程的优先数或轮转时间片数、以及进程需要运行的时间片数,均由伪随机数发生器产生。
通过本实验可以加深理解有关进程控制块、进程队列的概念,并体会和了解优先数和时间片轮转调度算法的具体实施办法。
2.主要功能
本程序可选用优先数法或简单轮转法对五个进程进行调度。
每个进程处于运行R(run)、就绪W(wait)和完成F(finish)三种状态之一,并假设起始状态都是就绪状态W。
为了便于处理,程序进程的运行时间以时间片为单位计算。
3.实现环境
本次课程设计结合算法的特点,采用Windows操作系统平台。
开发工具为Microsoft Visual C++6.0。
三、任务的分析、设计、实现和讨论
1、任务的分析
本程序可选用优先数法或简单轮转法对五个进程进行调度。
每个进程处于运行R(run)、就绪W(wait)和完成F(finish)三种状态之一,并假设起始状态都是就绪状态W。
为了便于处理,程序进程的运行时间以时间片为单位计算。
各进程的优先数或轮转时间片数、以及进程需要运行的时间片数,均由伪随机数发生器产生。
下面介绍优先数法和简单轮转法两种进程调度算法:
(1) 优先数法。
进程就绪链按优先数大小从高到低排列,链首进程首先投入运行。
每过一个时间片,运行进程所需运行的时间片数减1,说明它已运行了一个时间片,优先数也减3,理由是该进程如果在一个时间片中完成不了,优先级应该降低一级。
接着比较现行进程和就绪链链首进程的优先数,如果仍是现行进程高或者相同,就让现行进程继续进行,否则,调度就绪链链首进程投入运行。
原运行进程再按其优先数大小插入就绪链,且改变它们对应的进程状态,直至所有进程都运行完各自的时间片数。
(2) 简单轮转法。
进程就绪链按各进程进入的先后次序排列,进程每次占用处理机的轮转时间按其重要程度登入进程控制块中的轮转时间片数记录项(相当于优先数法的优先数记录项位置)。
每过一个时间片,运行进程占用处理机的时间片数加1,然后比较占用处理机的时间片数是否与该进程的轮转时间片数相等,若相等说明已到达轮转时间,应将现运行进程排到就绪链末尾,调度链首进程占用处理机,且改变它们的进程状态,直至所有进程完成各自的时间片。
进程控制块结构如下:
进程控制块链结构如下:
其中:RUN —当前运行进程指针;
HEAD —进程就绪链链首指针; TAID —进程就绪链链尾指针。
2、 任务的设计与实现
算法流程图:
3、操作过程和结果分析
优先数调度算法测试数据:
优先数调度算法程序运行结果截图:
图1.1 结果截图
图1.2 结果截图
简单轮转调度算法测试数据:
简单轮转调度算法程序运行结果截图:
图2.1 结果截图
图2.2 结果截图
图2.3 结果截图
4、思考题的解答和讨论
:
四、《操作系统》课程设计小结
当我在回首这一个星期的时候,不因虚度光阴而悔恨,也不因碌碌无为而羞耻。
我想,这可能是我一学期中最丰富而有意义的一个星期了。
从大一开始我的理论知识就比实践知识好的多,每门课都如此,实训是我最头疼的一件事。
课本上记得很牢的东西到了实际操作的时候感觉都用不上,做个实验就手忙脚乱的。
所以我感觉,这个星期的课设不仅学到了在理论课上学不到的知识,更是让我对自己的实践操作有了信心。
本次课程设计的题目之一是进程调度——优先数法与简单轮转法。
在多任务系统中,进程调度是CPU管理的一项核心工作。
根据调度模式的不同,多任务系统有两种类型,即非抢占式和抢占式。
其中,优先数法是非抢占式调度策略,而简单轮转法是抢占式调度策略。
进程调度算法是系统效率的关键,它确定了系统对资源,特别是对CPU资源的分配策略,因而直接决定着系统最本质的性能指标,如相应速度和吞吐量等。
常用的调度算法有:先进先出法,短进程优先法,时间片轮转法(时间片轮转法还分为可变时间片轮转法和简单循环轮转法),优先级调度法。
简单循环轮转法中的时间片q是一个十分重要的因素,它的计算公式为q=t/n。
q的选择对进程调度有很大的影响。
q取的太大,轮转法就会退化成先进先出算法;而取的太小,则会导致系统开销增加,将时间浪费在进程切换上。
所以q必须取值适中,使就绪队列中的所有进程都能得到同样的服务。
但我们这次的实验中暂时还没有考虑到时间片q 对算法的影响,只是测试了这个调度策略的算法。
这次我们的实验测试并比较了简单轮转法和优先数法这两种调度策略的性能。
不同的算法有它自己不同的长处,简单轮转法虽然能够使每个进程可以以相等的速度向前进展,但对于紧急进程的处理就显然不及优先数法。
可是优先数法的开销较高,而且可能对于较短而且优先级低的进程会花较长的时间等待。
不过它还是具有良好的均衡性。
实际应用中,经常是多种策略结合使用。
如时间片轮转法中也可以适当考虑优先级因素,对于紧急的进程可以分配一个长一点的时间片,或连续运行多个时间片等。
这样取长补短,合理利用各种不同算法的优势,让CPU的运行效率大大提高。
人们总是在寻找更好的解决方案,让算法的性能和开销得到一个相对较好的平衡。
我在寻找这样的一个解决方案时,同学对我说虽然老师没有在课上讲过这个策略,但其实书上有关于更好的调度策略。
也就是多级反馈队列调度。
这种算法可以先用较小的时间片处理完那些用时较短的进程,而给那些用时较长的进程分配较大的时间片,以免较长的进程频繁被中断而影响处理机的效率。
这也就是上面所提到的“多种策略结合使用,如时间片轮转法中也可以适当考虑优先级因素”。
温故而知新,可以为师矣。
这次编程中所用到的C语言正是我们大一就学过的计算机语言。
在平时的学习中和实训中我们总能用到它。
这样反复的运用和考核,让我对C语言的认识更进了一步。
路漫漫其修远兮,吾将上下而求索。
我们对操作系统的学习还有很长的路要走,死锁只是其中的一小部分。
重要的是,我在实训的这种里学到了这样的一种精神,一种知难而上,相信努力和付出能够带来好的结果的精神。
这种精神比刻板的知识点更加重要,能够指引我走向更宽阔的明天。
五、附录
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef struct node
{
char name[10]; /*进程标识符*/
int prio; /*进程优先数*/
int round; /*进程时间轮转时间片*/
int cputime; /*进程占用CPU时间*/
int needtime; /*进程到完成还要的时间*/
int count; /*计数器*/
char state; /*进程的状态*/
struct node *next; /*链指针*/
}PCB;
PCB *finish,*ready=NULL,*tail,*run,*pfcfs,*pfcfs1; /*队列指针*/
int N; /*进程数*/
/*将就绪队列中的第一个进程投入运行*/
void firstin()
{
run=ready; /*就绪队列头指针赋值给运行头指针*/
run->state='R'; /*进程状态变为运行态*/
ready=ready->next; /*就绪对列头指针后移到下一进程*/
}
/*标题输出函数*/
void prt1(char a)
{
if(toupper(a)=='P') /*优先数法*/
printf(" name cputime needtime priority state\n");
else if(toupper(a)=='R')
printf(" name cputime needtime count round state\n");
}
/*进程PCB输出*/
void prt2(char a,PCB *q)
{
if(toupper(a)=='P') /*优先数法的输出*/
printf("%-10s%-10d%-10d%-10d%c\n",q->name,q->cputime,q->needtime,q->prio,q->state);
else if(toupper(a)=='R')/*轮转法的输出*/
printf("%-10s%-10d%-10d%-10d%-10d%-c\n",q->name,q->cputime,q->needtime,q->count,q->roun d,q->state);
}
/*输出函数*/
void prt(char algo)
{
PCB *p;
prt1(algo); /*输出标题*/
if(run!=NULL) /*如果运行指针不空*/
prt2(algo,run); /*输出当前正在运行的PCB*/
p=ready; /*输出就绪队列PCB*/
while(p!=NULL)
{
prt2(algo,p);
p=p->next;
}
p=finish; /*输出完成队列的PCB*/
while(p!=NULL)
{
prt2(algo,p);
p=p->next;
}
getchar(); /*压任意键继续*/
}
/*优先数的插入算法*/
void insert1(PCB *q)
{
PCB *p1,*s,*r;
int b;
s=q; /*待插入的PCB指针*/
p1=ready; /*就绪队列头指针*/
r=p1; /*r做p1的前驱指针*/
b=1;
while((p1!=NULL)&&b) /*根据优先数确定插入位置*/
if(p1->prio>=s->prio)
{
r=p1;
p1=p1->next;
}
else
b=0;
if(r!=p1) /*如果条件成立说明插入在r与p1之间*/
{
r->next=s;
s->next=p1;
}
else
{
s->next=p1; /*否则插入在就绪队列的头*/
ready=s;
}
}
/*轮转法插入函数*/
void insert2(PCB *p2)
{
tail->next=p2; /*将新的PCB插入在当前就绪队列的尾*/ tail=p2;
p2->next=NULL;
}
void insert3()/*先来先服务*/
{
if (ready==NULL)
{ ready=pfcfs;
ready->next=NULL;
pfcfs1=pfcfs;
}
else
{pfcfs1->next=pfcfs;
pfcfs1=pfcfs1->next;
}
}
/*优先数创建初始PCB信息*/
void create1(char alg)
{
PCB *p;
int i,time;
char na[10];
ready=NULL; /*就绪队列头指针*/
finish=NULL; /*完成队列头指针*/
run=NULL; /*运行队列指针*/
for(i=1;i<=N;i++)
{
p=(struct node*)malloc(sizeof(PCB));
printf("请输入进程名称%d\n",i);
scanf("%s",na);
printf("请输入进程运行时间\n");
scanf("%d",&time);
strcpy(p->name,na);
p->cputime=0;
p->needtime=time;
p->state='w';
p->prio=50-time;
if(ready!=NULL) /*就绪队列不空调用插入函数插入*/
insert1(p);
else
{
p->next=ready; /*创建就绪队列的第一个PCB*/
ready=p;
}
}
printf(" 最高优先级进程调度模拟:\n");
printf("************************************************\n"); prt(alg); /*输出进程PCB信息*/
printf("************************************************\n"); run=ready; /*将就绪队列的第一个进程投入运行*/
ready=ready->next;
run->state='R';}
/*轮转法创建进程PCB*/
void create2(char alg)
{
PCB *p;
int i,time;
char na[10];
ready=NULL;
finish=NULL;
run=NULL;
for(i=1;i<=N;i++)
{
p=(struct node *)malloc(sizeof(PCB));
printf("请输入进程名称%d\n",i);
scanf("%s",na);
printf("请输入进程运行时间\n");
scanf("%d",&time);
strcpy(p->name,na);
p->cputime=0;
p->needtime=time;
p->count=0; /*计数器*/
p->state='w';
p->round=2; /*时间片*/
if(ready!=NULL)
insert2(p);
else
{
p->next=ready;
ready=p;
tail=p;
}
}
printf(" 时间轮转法进程调度模拟\n");
printf("************************************************\n");
prt(alg); /*输出进程PCB信息*/
printf("************************************************\n");
run=ready; /*将就绪队列的第一个进程投入运行*/
ready=ready->next;
run->state='R';
}
/*优先数调度算法*/
void priority(char alg)
{
while(run!=NULL) /*当运行队列不空时,有进程正在运行*/
{
run->cputime=run->cputime+1;
run->needtime=run->needtime-1;
run->prio=run->prio-3; /*每运行一次优先数降低3个单位*/
if(run->needtime==0) /*如所需时间为0将其插入完成队列*/
{
run->next=finish;
finish=run;
run->state='F'; /*置状态为完成态*/
run=NULL; /*运行队列头指针为空*/
if(ready!=NULL) /*如就绪队列不空*/
firstin(); /*将就绪对列的第一个进程投入运行*/
}
else /*没有运行完同时优先数不是最大,则将其变为就绪态插入到就绪列*/ if((ready!=NULL)&&(run->prio<ready->prio))
{
run->state='W';
insert1(run);
firstin(); /*将就绪队列的第一个进程投入运行*/
}
prt(alg); /*输出进程PCB信息*/
}
}
/*时间片轮转法*/
void roundrun(char alg)
{
while(run!=NULL)
{
run->cputime=run->cputime+1;
run->needtime=run->needtime-1;
run->count=run->count+1;
if(run->needtime==0)/*运行完将其变为完成态,插入完成队列*/ {
run->next=finish;
finish=run;
run->state='F';
run=NULL;
if(ready!=NULL)
firstin(); /*就绪对列不空,将第一个进程投入运行*/
}
else
if(run->count==run->round) /*如果时间片到*/
{
run->count=0; /*计数器置0*/
if(ready!=NULL) /*如就绪队列不空*/
{
run->state='W'; /*将进程插入到就绪队列中等待轮转*/
insert2(run);
firstin(); /*将就绪对列的第一个进程投入运行*/
}
}
prt(alg); /*输出进程信息*/
}
}
int check_char(char algo)/*判断输入的字符是否有效*/
{if (algo=='F'||algo=='f'||algo=='R'||algo=='r'||algo=='P'||algo=='p') return 1;
else
return 0;
}
/*主函数*/
void main()
{
char algo; /*算法标记*/
int len,h=0;
char ch/*接收换行字符*/;
printf("\n***********请选择要模拟的算法***************\n\n"); printf("1.最高优先数进程调度算法模拟(P/p)\n");
printf("2.时间轮转法进程调度算法模拟(R/r)\n");
printf("请输入相应字符选择\n\n");
scanf("%c",&algo); /*输入字符确定算法*/
if(check_char(algo))/*判断输入的字符是否合法*/
{
printf("请输入进程调度个数\n");
scanf("%d",&N); /*输入进程数*/
if(algo=='P'||algo=='p')
{
create1(algo); /*优先数法*/
priority(algo);
printf("\n\n 进程已经完成.\n");
}
else
if(algo=='R'||algo=='r')
{
create2(algo); /*轮转法*/
roundrun(algo);
printf("\n\n 进程已经完成.\n");
}
}
else if(!check_char(algo)) printf("你输入的字符有误,请重新运行程序!!"); }。