zoukankan      html  css  js  c++  java
  • 多级反馈队列调度算法

     

     

     

    实 验 报 告(拓展实验1)

    多级反馈队列调度算法

     

     

    课程名称 操作系统实验

    学生学院 计算机学院

    专业班级 17网络工程一班

    学 号 31170050**

    学生姓名 陈鸿

    指导教师 林穗

     

     

     

     

     

    2019 12 6

     

    目录

    一、    实验目的    3

    二、实验内容    3

    多级反馈队列调度算法的概念:    3

    应用范围:    3

    三、实现思路    4

    四、主要的数据结构    4

    void Output(); /*进程信息输出函数*/    5

    void InsertFinish(PCB *in); /*将进程插入到完成队列尾部*/    5

    void InsertPrio(ReadyQueue *in); /*创建就绪队列,规定优先数越小,优先级越低*/    5

    void PrioCreate(); /*创建就绪队列输入函数*/    5

    void GetFirst(ReadyQueue *queue); /*取得某一个就绪队列中的队头进程*/    5

    void InsertLast(PCB *in,ReadyQueue *queue); /*将进程插入到就绪队列尾部*/    5

    void ProcessCreate(); /*进程创建函数*/    5

    void RoundRun(ReadyQueue *timechip); /*时间片轮转调度算法*/    5

    void MultiDispatch(); /*多级调度算法,每次执行一个时间片*/    5

    int main(void)    6

    五、算法流程图    12

    六、运行与测试    12

    用例描述:    12

    运行截图:    13

    七、总结    13

     

     

     

     

     

     

     

     

     

     

    Tips:建议打开word【导航视图】与【批注】阅读。

     

    拓展实验1:多级反馈队列调度算法

    1. 实验目的

    分析操作系统的核心功能模块,理解相关功能模块实现的数据结构和算法,并加以实现,加深对操作系统原理和实现过程的理解。本次实验: 分析并实现多级反馈队列调度算法的模拟。

     

    二、实验内容

    多级反馈队列调度算法的概念:

    是一种根据先来先服务原则给就绪队列排序,为就绪队列赋予不同的优先级数,不同的时间片,按照优先级抢占CPU的调度算法。算法的实施过程如下:

     

    (1)按照先来先服务原则排序,设置N个就绪队列为Q1,Q2...QN,每个队列中都可以放很多作业;

    (2)为这N个就绪队列赋予不同的优先级,第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低;

    (3)设置每个就绪队列的时间片,优先权越高,算法赋予队列的时间片越小。时间片大小的设定按照实际作业(进程)的需要调整;

    (4)进程在进入待调度的队列等待时,首先进入优先级最高的Q1等待。

    (5)首先调度优先级高的队列中的进程。若高优先级中队列中已没有调度的进程,则调度次优先级队列中的进程。例如:Q1,Q2,Q3三个队列,只有在Q1中没有进程等待时才去调度Q2,同理,只有Q1,Q2都为空时才会去调度Q3。

    (6)对于同一个队列中的各个进程,按照时间片轮转法调度。比如Q1队列的时间片为N,那么Q1中的作业在经历了时间片为N的时间后,若还没有完成,则进入Q2队列等待,若Q2的时间片用完后作业还不能完成,一直进入下一级队列,直至完成。

    (7)在低优先级的队列中的进程在运行时,又有新到达的作业,那么在运行完这个时间片后,CPU马上分配给新到达的作业即抢占式调度CPU。

     

    应用范围:

    此算法应用于同一个资源的多个使用者可分优先级使用资源的情况。

    三、实现思路

    1、设置多个就绪队列,并给队列赋予不同的优先级数,第一个最高,依次递减。

     

    2、赋予各个队列中进程执行时间片的大小,优先级越高的队列,时间片越小。

     

    3、当一个新进程进入内存后,首先将其放入一个对列末尾,如果在一个时间片

    结束时尚未完成,将其转入第二队列末尾。

     

    4、当一个进程从一个对列移至第n个队列后,便在第n个队列中采用时间片轮转执行完。

     

    5、仅当时间片空闲时,才调度第二个队列中的进程。

    (1~i-1)空闲时,才调度i,如果处理机正在第i队列中运行,又有新进程进入优先权较高

    队列,则新进程抢占处理机,将正在运行的进程放入第i队列队尾,将处理机分给新进程。

     

    四、主要的数据结构

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    typedef struct node /*进程节点信息*/

    {

    char name[20]; /*进程的名字*/

    int prio; /*进程的优先级*/

    int round; /*分配CPU的时间片*/

    int cputime; /*CPU执行时间*/

    int needtime; /*进程执行所需要的时间*/

    char state; /*进程的状态,W--就绪态,R--执行态,F--完成态*/

    int count; /*记录执行的次数*/

    struct node *next; /*链表指针*/

    }PCB;

    typedef struct Queue /*多级就绪队列节点信息*/

    {

    PCB *LinkPCB; /*就绪队列中的进程队列指针*/

    int prio; /*本就绪队列的优先级*/

    int round; /*本就绪队列所分配的时间片*/

    struct Queue *next; /*指向下一个就绪队列的链表指针*/

    }ReadyQueue;

    PCB *run=NULL,*finish=NULL; /*定义三个队列,就绪队列,执行队列和完成队列*/

    ReadyQueue *Head = NULL; /*定义第一个就绪队列*/

    int num; /*进程个数*/

    int ReadyNum; /*就绪队列个数*/

     

    void Output(); /*进程信息输出函数*/

    void InsertFinish(PCB *in); /*将进程插入到完成队列尾部*/

    void InsertPrio(ReadyQueue *in); /*创建就绪队列,规定优先数越小,优先级越低*/

    void PrioCreate(); /*创建就绪队列输入函数*/

    void GetFirst(ReadyQueue *queue); /*取得某一个就绪队列中的队头进程*/

    void InsertLast(PCB *in,ReadyQueue *queue); /*将进程插入到就绪队列尾部*/

    void ProcessCreate(); /*进程创建函数*/

    void RoundRun(ReadyQueue *timechip); /*时间片轮转调度算法*/

    void MultiDispatch(); /*多级调度算法,每次执行一个时间片*/

     

     

    int main(void)

    {

    PrioCreate(); /*创建就绪队列*/

    ProcessCreate();/*创建就绪进程队列*/

    MultiDispatch();/*算法开始*/

    Output(); /*输出最终的调度序列*/

    return 0;

    }

    void Output() /*进程信息输出函数*/

    {

    ReadyQueue *print = Head;

    PCB *p;

    printf("进程名 优先级 轮数 cpu时间 需要时间 进程状态 计数器 ");

    while(print)

    {

    if(print ->LinkPCB != NULL)

    {

    p=print ->LinkPCB;

    while(p)

    {

    printf("%s %d %d %d %d %c %d ",p->name,p->prio,p->round,p->cputime,p->needtime,p->state,p->count);

    p = p->next;

                     }

             }

    print = print->next;

         }

    p = finish;

    while(p!=NULL)

    {

    printf("%s %d %d %d %d %c %d ",p->name,p->prio,p->round,p->cputime,p->needtime,p->state,p->count);

    p = p->next;

    }

    p = run;

    while(p!=NULL)

    {

    printf("%s %d %d %d %d %c %d ",p->name,p->prio,p->round,p->cputime,p->needtime,p->state,p->count);

    p = p->next;

    }

    }

    void InsertFinish(PCB *in) /*将进程插入到完成队列尾部*/ {

    PCB *fst;

    fst = finish;

    if(finish == NULL)

    {

    in->next = finish;

    finish = in;

    }

    else

    {

    while(fst->next != NULL)

    {

    fst = fst->next;

             }

    in ->next = fst ->next;

    fst ->next = in;

    }

    }

    void InsertPrio(ReadyQueue *in) /*创建就绪队列,规定优先数越小,优先级越低*/

    {

    ReadyQueue *fst,*nxt;

    fst = nxt = Head;

    if(Head == NULL) /*如果没有队列,则为第一个元素*/

    {

    in->next = Head;

    Head = in;

    }

    else /*查到合适的位置进行插入*/

    {

    if(in ->prio >= fst ->prio) /*比第一个还要大,则插入到队头*/

    {

    in->next = Head;

    Head = in;

    }

    else

    {

    while(fst->next != NULL) /*移动指针查找第一个别它小的元素的位置进行插入*/

    {

    nxt = fst;

    fst = fst->next;

                     }

    if(fst ->next == NULL) /*已经搜索到队尾,则其优先级数最小,将其插入到队尾即可*/

    {

    in ->next = fst ->next;

    fst ->next = in;

    }

    else /*插入到队列中*/

    {

    nxt = in;

    in ->next = fst;

    }

    }

    }

    }

    void PrioCreate() /*创建就绪队列输入函数*/

    {

    ReadyQueue *tmp;

    int i;

    printf("输入就绪队列的个数: ");

    scanf("%d",&ReadyNum);

     

    printf("输入每个就绪队列的CPU时间片: ");

    for(i = 0;i < ReadyNum; i++)

    {

    if((tmp = (ReadyQueue *)malloc(sizeof(ReadyQueue)))==NULL)

    {

    perror("malloc");

    exit(1);

    }

    scanf("%d",&(tmp->round)); /*输入此就绪队列中给每个进程所分配的CPU时间片*/

    tmp ->prio = 50 - tmp->round; /*设置其优先级,时间片越高,其优先级越低*/

    tmp ->LinkPCB = NULL; /*初始化其连接的进程队列为空*/

    tmp ->next = NULL;

    InsertPrio(tmp); /*按照优先级从高到低,建立多个就绪队列*/

    }

    }

    void GetFirst(ReadyQueue *queue) /*取得某一个就绪队列中的队头进程*/

    {

    run = queue ->LinkPCB;

    if(queue ->LinkPCB != NULL)

    {

    run ->state = 'R';

    queue ->LinkPCB = queue ->LinkPCB ->next;

    run ->next = NULL;

    }

    }

    void InsertLast(PCB *in,ReadyQueue *queue) /*将进程插入到就绪队列尾部*/

    {

    PCB *fst;

    fst = queue->LinkPCB;

    if( queue->LinkPCB == NULL)

    {

    in->next = queue->LinkPCB;

    queue->LinkPCB = in;

    }

    else

    {

    while(fst->next != NULL)

    {

    fst = fst->next;

    }

    in ->next = fst ->next;

    fst ->next = in;

    }

    }

    void ProcessCreate() /*进程创建函数*/

    {

    PCB *tmp;

    int i;

     

    printf("输入进程的个数: ");

    scanf("%d",&num);

    printf("输入进程名字和进程所需时间: ");

    for(i = 0;i < num; i++)

    {

    if((tmp = (PCB *)malloc(sizeof(PCB)))==NULL)

    {

    perror("malloc");

    exit(1);

    }

    scanf("%s",tmp->name);

    getchar(); /*吸收回车符号*/

    scanf("%d",&(tmp->needtime));

    tmp ->cputime = 0;

    tmp ->state ='W';

    tmp ->prio = 50 - tmp->needtime; /*设置其优先级,需要的时间越多,优先级越低*/

    tmp ->round = Head ->round;

    tmp ->count = 0;

    InsertLast(tmp,Head); /*按照优先级从高到低,插入到就绪队列*/

    }

    }

    void RoundRun(ReadyQueue *timechip) /*时间片轮转调度算法*/

    {

    int flag = 1;

    GetFirst(timechip);

    while(run != NULL)

    {

    while(flag)

    {

    run->count++;

    run->cputime++;

    run->needtime--;

    if(run->needtime == 0) /*进程执行完毕*/

    {

    run ->state = 'F';

    InsertFinish(run);

    flag = 0;

    }

    else if(run->count == timechip ->round)/*时间片用完*/

    {

    run->state = 'W';

    run->count = 0; /*计数器清零,为下次做准备*/

    InsertLast(run,timechip);

    flag = 0;

    }

    }

    flag = 1;

    GetFirst(timechip);

    }

    }

    void MultiDispatch() /*多级调度算法,每次执行一个时间片*/

    {

    int flag = 1;

    int k = 0;

    ReadyQueue *point;

    point = Head;

    GetFirst(point);

    while(run != NULL)

    {

    Output();

    if(Head ->LinkPCB!=NULL)

    point = Head;

    while(flag) {

    run->count++;

    run->cputime++;

    run->needtime--;

    if(run->needtime == 0) /*进程执行完毕*/

    {

    run ->state = 'F';

    InsertFinish(run);

    flag = 0;

    }

    else if(run->count == run->round)/*时间片用完*/

    {

    run->state = 'W';

    run->count = 0; /*计数器清零,为下次做准备*/

    if(point ->next!=NULL)

    {

    run ->round = point->next ->round;/*设置其时间片是下一个就绪队列的时间片*/

    InsertLast(run,point->next); /*将进程插入到下一个就绪队列中*/

    flag = 0;

    }

    else {

    RoundRun(point); /*如果为最后一个就绪队列就调用时间片轮转算法*/

    break;

    }

    }

    ++k;

    if(k == 3) {

    ProcessCreate();

    }

    }

    flag = 1;

    if(point ->LinkPCB == NULL)/*就绪队列指针下移*/

    point =point->next;

    if(point ->next ==NULL)

    {

    RoundRun(point);

    break;

    }

    GetFirst(point);

    }

    }

    五、算法流程图

    六、运行与测试

    用例描述:

     

    假设系统中有3个就绪队列Q1,Q2,Q3,时间片分别为2,4,8

    现在有3个作业J1,J2,J3它们所需要的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再经过一个时间片,完成了任务。于是整个调度过程结束。

     

     

     

     

    运行截图:

    七、总结

     

    多级反馈队列调度算法体现了计算思维的调度特点,应用了先来先服务原则、应用时间片等做法使得每个申请者都能及时使用资源,是一种很好的协调整体的解决方案。

    不积跬步,无以至千里;不积小流,无以成江海。
  • 相关阅读:
    PAT1065. A+B and C (64bit)
    PAT1064. Complete Binary Search Tree
    PAT 1063. Set Similarity
    CodeForces
    Golang在京东列表页实践总结
    asp.net 5 如何使用ioc 以及在如何获取httpcontext对象
    陨石坑之webapi 使用filter中如何结束请求流
    陨石坑之webapi使用filter
    Socket通信前必须考虑的几件事
    ZeroMQ的进阶
  • 原文地址:https://www.cnblogs.com/CCTVCHCH/p/14923957.html
Copyright © 2011-2022 走看看