在多道程序环境下,主存中有着多个进程,其数目往往多过于处理机数目。
这就要求系统能按某种算法,动态的把处理机分配给就绪队列中的一个进程,使之执行。
在OS中的调度的实质是一种资源分配,因而调度算法是指:根据系统的资源分配策略所规定的资源分配算法。
对于不同的系统和系统目标,通常采用不同的调度算法,目前存在的多种调度算法中,有的算法适用于作业电镀,有的算法适用于进程调度;但也有些调度算法即可用于作业调度,也可用于进程调度。
多级反馈队列调度算法是一种CPU处理机调度算法,它不必事先知道各种进程所需的执行时间,而且还可以满足各种类型进程的需要,因而它是目前被公认的一种较好的进程调度算法。
多级反馈队列调度算法的思想设置多个就绪队列,并为各个队列赋予不同的优先级和不同长度的时间片;第一个队列的优先级最高,进程所执行时间片最小。
新创建的进程挂到第一优先级的队列后,然后按FCFS 原则排队等待调度。
当轮到其执行时,如它能在时间片内完成,便撤离系统;如果不能完成,便被挂入第二级队列后,……;仅当第一级队列空闲时,调度程序才调度第二级队列中的进程运行,依次类推……;新进程可抢占低级进程的处理机。
多级(假设为N级)反馈队列调度算法可以如下原理:1、设有N个队列(Q1,Q2....QN),其中各个队列对于处理机的优先级是不一样的,也就是说位于各个队列中的作业(进程)的优先级也是不一样的。
一般来说,优先级Priority(Q1) > Priority(Q2) > ... >Priority(QN)。
怎么讲,位于Q1中的任何一个作业(进程)都要比Q2中的任何一个作业(进程)相对于CPU的优先级要高(也就是说,Q1中的作业一定要比Q2中的作业先被处理机调度),依次类推其它的队列。
2、对于某个特定的队列来说,里面是遵循时间片轮转法。
也就是说,位于队列Q2中有N个作业,它们的运行时间是通过Q2这个队列所设定的时间片来确定的(为了便于理解,我们也可以认为特定队列中的作业的优先级是按照FCFS来调度的)。
3、各个队列的时间片是一样的吗?不一样,这就是该算法设计的精妙之处。
各个队列的时间片是随着优先级的增加而减少的,也就是说,优先级越高的队列中它的时间片就越短。
同时,为了便于那些超大作业的完成,最后一个队列QN(优先级最低的队列)的时间片一般很大(不需要考虑这个问题)。
多级反馈队列调度算法描述:1、进程在进入待调度的队列等待时,首先进入优先级最高的Q1等待。
2、首先调度优先级高的队列中的进程。
若高优先级中队列中已没有调度的进程,则调度次优先级队列中的进程。
例如:Q1,Q2,Q3三个队列,只有在Q1中没有进程等待时才去调度Q2,同理,只有Q1,Q2都为空时才会去调度Q3。
3、对于同一个队列中的各个进程,按照时间片轮转法调度。
比如Q1队列的时间片为N,那么Q1中的作业在经历了N个时间片后若还没有完成,则进入Q2队列等待,若Q2的时间片用完后作业还不能完成,一直进入下一级队列,直至完成。
4、在低优先级的队列中的进程在运行时,又有新到达的作业,那么在运行完这个时间片后,CPU马上分配给新到达的作业(抢占式)。
我们来看一下该算法是如何运作的:假设系统中有3个反馈队列Q1,Q2,Q3,时间片分别为2,4,8。
现在有3个作业J1,J2,J3分别在时间 0 ,1,3时刻到达。
而它们所需要的CPU时间分别是3,2,1个时间片。
1、时刻0 J1到达。
于是进入到队列1 ,运行1个时间片,时间片还未到,此时J2到达。
2、时刻1 J2到达。
由于时间片仍然由J1掌控,于是等待。
J1在运行了1个时间片后,已经完成了在Q1中的2个时间片的限制,于是J1置于Q2等待被调度。
现在处理机分配给J2。
3、时刻2 J1进入Q2等待调度,J2获得CPU开始运行。
4、时刻3 J3到达,由于J2的时间片未到,故J3在Q1等待调度,J1也在Q2等待调度。
5、时刻4 J2处理完成,由于J3,J1都在等待调度,但是J3所在的队列比J1所在的队列的优先级要高,于是J3被调度,J1继续在Q2等待。
6、时刻5 J3经过1个时间片,完成。
7、时刻6 由于Q1已经空闲,于是开始调度Q2中的作业,则J1得到处理器开始运行。
8、时刻7 J1再经过一个时间片,完成了任务。
于是整个调度过程结束。
从上面的例子看,在多级反馈队列中,后进的作业不一定慢完成。
FCFS、SJF和优先级调度算法仅对某一类作业有利,相比之下,它能全面满足不同类型作业的需求,较好实现公平性与资源利用率之间的平衡。
对交互型作业,由于通常较短,这些作业在第一队列规定的时间片内完成,可使用户感到满意;对短批作业,开始时在第一队列中执行一个时间片就可完成,便可与交互型作业一样获得快速晌应,否则通常也仅需在第二、第三队列中各执行一个时间片即可完成,其周转时间仍较短;对长批作业,它们依次在第一至第n个队列中轮番执行,不必担心长时间得不到处理。
多级队列调度算法的性能终端型用户:由于终端型用户所提交的作业大多属于交互型作业,作业通常都比较小,系统只要能够使这些作业在第一队列所规定的时间片内完成,便可以使终端型用户感到满意。
短批处理作业用户:对于很短的批处理型作业,开始时象终端型作业一样,如果仅在第一队列中执行一个时间片即可完成,便可以获得与终端型作业一样的响应时间。
对于稍长的作业,通常也只需要在第二队列和第三队列各执行一个时间片即可完成,周转时间还是比较短。
长批处理作业用户:对于长作业,他将依次在n个队列中运行,然后按照轮转的方法运行,用户不必担心其作业长期得不到处理。
多级反馈队列调度实现思想允许进程在队列之间移动。
在系统中设置多个就绪队列,每个队列对应一个优先级,第一个队列的优先级最高,第二队列次之。
以下各队列的优先级逐步低。
各就绪队列中的进程的运行时间片不同,高优先级队列的时间片小,低优先级队列的时间片大。
进程并非总是固定在某一队列中,新进程进入系统后,被存放在第一个队列的末尾。
如果某个进程在规定的时间片内没有完成工作,则把它转入到下一个队列的末尾,直至进入最后一个队列。
系统先运行第一个队列中的进程。
当第一队列为空时,才运行第二个队列中的进程。
依此类推,仅当前面所有的队列都为空时,才运行最后一个队列中的进程。
当处理器正在第i个队列中为某个进程服务时,又有新进程进入优先级最高的队列(第1—(i-1)中的任何一个对列),则此新进程要抢占正在运行进程的处理器,即由调度程序把正在运行的进程放回第i队列的末尾,把处理器分配给新到的高优先级进程。
除最低优先权队列外的所有其他队列,均采用相同的进程调度算法,即按时间片轮转的FIFO(先进先出)算法。
最后一个队列中的进程按按时间片轮转或FCFS策略进行调度。
它是综合了FIFO、RR和剥夺式HPF的一种进程调度算法#include <stdio.h>#include <stdlib.h>#define M 3//队列总数#define N 5//进程总数typedef struct pcb{int id;//进程号int intime;//提交时间int priority;//优先级int starttime;//开始执行时间int length;//进程长度大小int endtime;//结束时间char state;//状态int ptime;//时间片struct pcb *next;}*PCB,pcb;//进程控制块PCB CreatReady(PCB R,int i){R=(PCB)malloc(sizeof(pcb));R->id=i+1;R->priority=5-i;R->ptime=i+1;R->state='R';R->next=NULL;printf("第%d级:\t%d\t%d\n",R->id,R->priority,R->ptime);return R;}PCB CreatWait(PCB W){int i;pcb *p,*q;q=W;printf("给进程初始化如下(tab键隔开):\n");printf("进程\tin时间\t优先级\t长度\n");for(i=0;i<N;i++){p=(PCB)malloc(sizeof(pcb));p->next=NULL;p->id=i+1;printf("P%d\t",p->id);scanf("%d\t%d\t%d",&p->intime,&p->priority,&p->length);q->next=p;q=p;}return W;}void Insert(PCB R,pcb *cp){pcb *tail;tail=R;while(tail->next){tail=tail->next;}tail->next=cp;cp->next=NULL;}int FindQuery(PCB R[M]){int i,j;for(i=0;i<M;i++){if(R[i]->next){j=i;break;}elseprintf("第%d级就绪队列为空\n",R[i]->id);}return j;}int Dispatch(PCB R,pcb *cp,PCB W,int time,pcb *tp){int s;pcb *p,*phead;phead=W;p=W->next;cp->starttime=time;cp->length-=R->ptime;cp->endtime=cp->starttime+R->ptime;if(cp->length<=0){s=1;//表示完成cp->endtime+=cp->length;}else{if(p){while(p){if((p->intime<cp->endtime)&&(p->priority>cp->priority)){tp->id=p->id;tp->intime=p->intime;tp->length=p->length;tp->priority=p->priority;tp->state=p->state;//将抢占进程p备份到tp中phead->next=p->next;//从后备队列中删除抢占的进程cp->length +=cp->endtime-tp->intime;cp->endtime-=cp->endtime-tp->intime;s=-1;//表示被抢占break;}elseif(p->intime>=cp->endtime){s=0;//在后备队列中没有可以抢占的进程时break;}p=p->next;phead=phead->next;}//查找可以抢占cpu的优先级高的进程tp}else s=0;//在后备队列没有进程时}return s;}void Print(PCB F){pcb *p;p=F->next;while(p){printf("P%d\t结束时间:%d\n",p->id,p->endtime);p=p->next;}}PCB MFQ(PCB W,PCB R[M],PCB F){pcb *cp;//当前系统操作的进程pcb *tp;//抢占cpu的进程tp=(PCB)malloc(sizeof(pcb));tp->priority=0;tp->next=NULL;int time=0;//time表示系统当前时间int Finish=0;int i,have,j;int s;while(Finish<N){cp=W->next;if(cp&&cp->intime<=time){have=1;}elsehave=0;//判断当前时刻有无进程被提交if(have){i=0;W->next=cp->next;//从后备队列中删除cpInsert(R[0],cp);cp->priority=R[0]->priority;cp->state=R[0]->state;cp=R[0]->next;printf("%d时,P%d被提交入就绪队列%d\n",time,cp->id,R[0]->id);}//将新进程入第一级就绪队列else{i=FindQuery(R);//循环查找不为空的就绪队列cp=R[i]->next;printf("%d时,无可以提交的进程,因此转到就绪队列%d执行P%d\n",time,R[i]->id,cp->id);}s=Dispatch(R[i],cp,W,time,tp);//cpu执行进程,并生成三种结果if(s==1){R[i]->next=cp->next;//从就绪队列中删除已完成的进程Insert(F,cp);Finish++;printf("%d时,P%d处理完成!\n",cp->endtime,cp->id);}if(s==0){if(i<2) j=i+1;else j=i;R[i]->next=cp->next;//从就绪队列中删除时间片耗尽的进程Insert(R[j],cp);cp->priority=R[j]->priority;printf("%d时,P%d因时间片耗尽进入下一级就绪队列%d!\n",cp->endtime,cp->id,R[j]->id);}if(s==-1){R[i]->next=cp->next;Insert(R[i],cp);tp->next=R[0]->next;R[0]->next=tp;tp->priority=R[0]->priority;tp->state=R[0]->state;//将抢占cpu的进程进入第一级就绪队列并首先执行printf("%d时,P%d被P%d抢占cpu并转入就绪队列%d队尾!\n",cp->endtime,cp->id,tp->id,R[i]->id);}time=cp->endtime;}return F;}void main (){PCB W;//后备队列PCB R[M];//就绪队列PCB F;//完成队列int i;printf("就绪队\t优先级\t时间片\n");for(i=0;i<M;i++){R[i]=CreatReady(R[i],i);}//创建就绪队列W=(PCB)malloc(sizeof(pcb));W->state='W';W->next=NULL;W=CreatWait(W);//创建后备队列F=(PCB)malloc(sizeof(pcb));F->state='F';F->next=NULL;//创建完成队列F=MFQ(W,R,F);//MFQ算法调度printf("完成队列如下:\n");Print(F);}。