zoukankan      html  css  js  c++  java
  • 【操作系统】多级反馈队列算法

    1. 原理介绍
    1. RR时间片轮转原理

          在采用时间片轮转算法中,所有的就绪进程按FCFS策略排成一个就绪队列。系统可设置每隔一定时间便产生一次中断,去激活进程调度程序进行调度,把CPU分配给队首进程,并令其执行一个时间片。当它运行完毕后,又把处理机分配给就绪队列中新的队首进程,也让它执行一个时间片。这样,就可以保证就绪队列中的所有进程在确定的时间段内,都能获得一个时间片的处理机时间。

        在RR调度算法中进程的切换,可分为两种情况:①若一个时间片尚未用完,正在运行的进程便已经完成,就立即激活调度程序,将它从就绪队列中删除,再调度就绪队列中队首的进程运行,并启动一个新的时间片。②在一个时间片用完时,计时器中断处理程序被激活。如果进程尚未运行完毕,调度程序将把它送往就绪队列的末尾。

       

      2.多级反馈队列调度机制

        设置多个就绪队列。在系统中设置多个就绪队列,并为每个队列赋予不同的优先。第一个队列的优先级最高,第二个次之,其余队列的优先级逐个降低。该算法为不同列中的进程所赋予的执行时间片的大小也各不相同,在优先级愈高的队列中,其时间片愈小。

        每个队列都采用FCFS算法。当新进程进入内存后,首先将它放入第一队列的末尾,按FCFS原则等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可撤离系统。否则,即它在一个时间片结束时尚未完成,调度程序将其转入第二队列的末尾等待调度;如果它在第二队列中运行个时间片后仍未完成, 再依次将它放入第三队列...依此类推。当进程最后被降到第n队列后,在第n队列中便采取按RR方式运行。

        按队列优先级调度。调度程序首先调度最高优先级队列中的诸进程运行,仅当第一队列空闲时才调度第二队列中的进程运行;仅当第1到(i-1)所有队列均空时,才会调度第i队列中的进程运行。如果处理机正在第i队列中为某进程服务时又有新进程进入任一优先级较高的队列,此时须立即把正在运行的进程放回到第i队列的末尾,而把处理机分配给新到的高优先级进程。

      

        2.设计原理

        PCB设计

        设计结构体PCB,其中包括进程的标识符,到达时间,服务时间,完成时间,周转时间和带权周转时间。利用动态数组将所有进程存储起来。

        

     1 struct PCB
     2 
     3 {
     4 
     5 int ID; //标识符
     6 
     7 int ComeTime; //到达时间
     8 
     9 int ServerTime; //服务时间
    10 
    11 int FinishTime; //完成时间
    12 
    13 int TurnoverTime; //周转时间
    14 
    15 double WeightedTurnoverTime; //带权周转时间
    16 
    17 };

      进程就绪队列

      采用STL中的队列设置3个队列,queue<PCB> Ready[3];

      时间片由数组timeslice[3]表示,大小分别为2,4,8。

      函数模块

      主函数模块分为3个模块:读入数据函数,多级反馈调度函数,输出函数。

      

      3.流程图

             

        4.代码实现

      1 #include <iostream>
      2 #include <algorithm>
      3 #include <iomanip>
      4 #include <vector>
      5 #include <queue>
      6 using namespace std;
      7  
      8 //作业结构体
      9 typedef struct PCB
     10 {
     11     int ID;                            //标识符
     12     int ComeTime;                    //到达时间
     13     int ServerTime;                    //服务时间
     14     int FinishTime;                    //完成时间
     15     int TurnoverTime;                //周转时间
     16     double WeightedTurnoverTime;    //带权周转时间
     17 }PCB;
     18 const int QueueNum = 3;//就绪队列长度     
     19 int timeslice[QueueNum];//第一个时间片 
     20 
     21 
     22  
     23 //输入作业信息
     24 void InputPCB(vector<PCB> &PCBList, int xlice[])
     25 {
     26     
     27     cout << "输入3个时间片大小: "<<endl;
     28     for(int i=0;i<3;i++){
     29         cin >> timeslice[i];
     30     } 
     31     
     32     while(1) {
     33         PCB temp;
     34         cout << "输入标识符   "<<"到达时间    "<<"服务时间 "<<endl;
     35         cin >> temp.ID>> temp.ComeTime>> temp.ServerTime;
     36         temp.FinishTime = 0;        //暂时存放运行了多少时间,来判断此作业是否运行结束
     37         PCBList.push_back(temp);
     38          cout<<"继续?Y/N:"<<endl;
     39         char n;
     40         cin>>n;
     41         if(n=='Y'||n=='y')
     42         continue;
     43         else 
     44         break; 
     45         
     46     }
     47 }
     48  
     49  
     50  bool CmpByComeTime(const PCB &p1, const PCB &p2)
     51 {
     52     return p1.ComeTime < p2.ComeTime;
     53 }
     54 
     55  
     56 //MFQ算法
     57 void MFQ(vector<PCB> &PCBList, int timeslice[])
     58 {
     59     sort(PCBList.begin(), PCBList.end(), CmpByComeTime);        //按到达时间排序
     60     vector<PCB> result;    //保存结果
     61     int BeginTime = (*PCBList.begin()).ComeTime;                    //第一个作业开始时间
     62     queue<PCB> Ready[QueueNum];        //设置3个就绪队列
     63     Ready[0].push(*PCBList.begin());
     64     PCBList.erase(PCBList.begin());
     65     cout<<"当前时刻:"<<BeginTime<<"   当前就绪队列:"<<0<<endl;
     66     cout<<"第一个进程进入就绪队列0"<<endl;
     67     cout<<endl;                
     68     while (!PCBList.empty())//进程数组不空 
     69     {
     70             //这段是为了防止前面的进程运行完了,后面的进程还没到,造成死循环
     71         bool flag = false;
     72         for (int i = 0; i < QueueNum; ++i)
     73         {
     74             if (!Ready[i].empty())
     75             {
     76                 flag = true;
     77                 break;
     78             }
     79         }
     80         if(!flag)
     81         {
     82             Ready[0].push(*PCBList.begin());
     83             PCBList.erase(PCBList.begin());
     84             BeginTime = Ready[0].front().ComeTime;
     85         }
     86  
     87         for (int i = 0; i < QueueNum; ++i)
     88         { 
     89         
     90             if (i != QueueNum - 1)        //不是最后一个队列
     91             {
     92                 while (!Ready[i].empty())    //当前队列不空
     93                 {
     94                     if (!PCBList.empty() && BeginTime>= (*PCBList.begin()).ComeTime)    //有新作业到达,加入就绪队列,转到第一队列
     95                     {
     96                         cout<<"当前时刻:"<<BeginTime<<endl;
     97                         cout<<"新进程"<<(*PCBList.begin()).ID<<"到达,将其放在第一队列尾部"<<endl;
     98                         cout<<endl;     
     99                         Ready[0].push(*PCBList.begin());
    100                         PCBList.erase(PCBList.begin());
    101                         i = 0; 
    102                         
    103                         continue;
    104                     }
    105  
    106                     if (Ready[i].front().FinishTime + timeslice[i] < Ready[i].front().ServerTime)        //时间片用完没运行完,加入下一队列队尾
    107                     {
    108                         cout<<"当前时刻:"<<BeginTime+ timeslice[i]<<"   当前就绪队列:"<<i<<endl;
    109                         cout<<"当前进程"<<Ready[i].front().ID<<"在时间片内没有运行完,加入下一个队列尾部!"<<endl; 
    110                         cout<<endl;    
    111                         
    112                         Ready[i].front().FinishTime += timeslice[i] ;
    113                         Ready[i + 1].push(Ready[i].front());//加入下一个队列 
    114                         Ready[i].pop();
    115                         BeginTime +=  timeslice[i] ;
    116                     }
    117                     else        //此作业运行完
    118                     {   
    119                         BeginTime += Ready[i].front().ServerTime - Ready[i].front().FinishTime;
    120                         Ready[i].front().FinishTime = BeginTime;
    121                         Ready[i].front().TurnoverTime = Ready[i].front().FinishTime - Ready[i].front().ComeTime;
    122                         Ready[i].front().WeightedTurnoverTime = (double)Ready[i].front().TurnoverTime / Ready[i].front().ServerTime;
    123                          cout<<"当前时刻:"<<BeginTime<<"   当前就绪队列:"<<i<<endl;
    124                          cout<<"当前进程"<<    Ready[i].front().ID<<"在时间片内运行完!"<<endl;
    125                          cout<<endl;    
    126                         //从就绪队列中移除作业
    127                         result.push_back(Ready[i].front());
    128                         Ready[i].pop();
    129                     }
    130                 }
    131             }
    132             else
    133             {
    134                 while (!Ready[i].empty())
    135                 {
    136                     if (!PCBList.empty() && BeginTime >= (*PCBList.begin()).ComeTime)    //有新作业到达,加入就绪队列,转到第一队列
    137                     {
    138                         cout<<"当前时刻:"<<BeginTime<<endl;
    139                         cout<<"新进程"<<(*PCBList.begin()).ID<<"到达,将其放在最后队列尾部"<<endl; 
    140                         cout<<endl;    
    141                         Ready[0].push(*PCBList.begin());
    142                         PCBList.erase(PCBList.begin());
    143                         i = -1;
    144                         break;
    145                     }
    146                     if (Ready[i].front().FinishTime + timeslice[i]  < Ready[i].front().ServerTime)        //时间片用完没运行完,加入队尾
    147                     {   cout<<"当前时刻:"<<BeginTime+ timeslice[i]<<"   当前就绪队列:"<<i<<endl;
    148                         cout<<"当前进程"<<Ready[i].front().ID<<"在时间片内没有运行完,加入该队列尾部!"<<endl; 
    149                         cout<<endl;    
    150                         Ready[i].front().FinishTime += timeslice[i] ;
    151                         Ready[i].push(Ready[i].front());
    152                         Ready[i].pop();
    153                         BeginTime +=  timeslice[i] ;
    154                     }
    155                     else        //此作业运行完
    156                     {
    157                         BeginTime += Ready[i].front().ServerTime - Ready[i].front().FinishTime;
    158                         Ready[i].front().FinishTime = BeginTime;
    159                         Ready[i].front().TurnoverTime = Ready[i].front().FinishTime - Ready[i].front().ComeTime;
    160                         Ready[i].front().WeightedTurnoverTime = (double)Ready[i].front().TurnoverTime / Ready[i].front().ServerTime;
    161                          cout<<"当前时刻:"<<BeginTime<<"   当前就绪队列:"<<i<<endl;
    162                         cout<<"当前进程"<<    Ready[i].front().ID<<"在时间片内运行完!"<<endl;
    163                         cout<<endl;    
    164                         //从就绪队列中移除作业
    165                         result.push_back(Ready[i].front());
    166                         Ready[i].pop();
    167                     }
    168                 }
    169             }
    170         }
    171     }
    172  
    173     //按ComeTime升序排序,便于显示结果
    174     PCBList = result;
    175     sort(PCBList.begin(), PCBList.end(), CmpByComeTime);
    176 }
    177  
    178 //显示结果
    179 void show(vector<PCB> &PCBList)
    180 {
    181     int SumTurnoverTime = 0;
    182     double SumWeightedTurnoverTime = 0;
    183  
    184     cout<<"标识符     "<<"达到时间    "<<"服务时间    "<<"完成时间    "<<"周转时间    "<<"带权周转时间" <<endl;
    185     
    186     for (vector<PCB>::iterator it = PCBList.begin(); it < PCBList.end(); ++it){
    187         cout<<(*it).ID<<"          "<<(*it).ComeTime<<"            "<< (*it).ServerTime<<"            "<<(*it).FinishTime<<"            "<<(*it).TurnoverTime<<"           "<< (*it).WeightedTurnoverTime<<endl;
    188         SumTurnoverTime+=(*it).TurnoverTime;
    189         SumWeightedTurnoverTime+=(*it).WeightedTurnoverTime;
    190     }
    191     
    192     cout << "平均周转时间: " << (double)SumTurnoverTime / PCBList.size() << endl;
    193     cout << "平均带权周转时间: " << SumWeightedTurnoverTime / PCBList.size() << endl;
    194 }
    195  
    196 //比较函数,按ComeTime升序排列
    197 
    198 
    199  
    200 int main()
    201 {
    202     vector<PCB> PCBList;//动态数组存放进程 
    203 
    204     InputPCB(PCBList, timeslice);//输入时间片大小,作业信息
    205  
    206     MFQ(PCBList, timeslice);
    207  
    208     show(PCBList);//显示结果
    209  
    210     return 0;
    211 }
    212  

        

          5.实例测试

     

    结果分析:

    如图5所示,0时刻,1进程到达,运行1个时间片2,此时进程没有运行完,加入下一队列,进程2到达,转到队列0调度进程2,运行1个时间片2,进入队列1队尾等待。

    时刻4开始,第一队列为空,此时调度第二队列,在进程1运行1个时间片4,没有运行完,加入队列2。

    时刻8,进程3到达,加入到第一队列尾部,调度进程3,进程3运行1个时间片2之后,加入下一队列。

    时刻10,队列1中进程2开始运行,时刻12运行结束。删除进程2.进程3开始运行,当前时间片内运行不完,加到队列2队尾。

    时刻16,进入队列2,调度进程1进行运行,时刻20,进程1运行结束,删除进程1。运行进程3,在当前时间片下不能运行完,则加入队列2。

    时刻28,进入队列2,调度进程3,时刻29运行完毕。

  • 相关阅读:
    phpcms 栏目图片循环调用
    phpcms调栏目图片
    Java 面向对象 --单例模式
    Java 面向对象 --包装类
    Java 面向对象 --匿名内部类
    Java面向对象--instanceof关键字
    Java 面向对象 --Object类
    Java 面向对象 --多态性
    Java 面向对象 --接口
    Java 面向对象 --抽象类
  • 原文地址:https://www.cnblogs.com/yitou13/p/10250285.html
Copyright © 2011-2022 走看看