作业调度的三种算法

作业调度的三种算法

一、先来先服务算法:

(1)按作业到达的先后次序进行调度。总是首先调度在系统中等待时间最长的作业。它是一种非剥夺式调度算法,主要是从“公平”的角度来考虑。哪个作业先进来,就优先执行哪个作业,不会导致饥饿,但是会出现作业的带权周转时间很大。
(2)代码如下:

#include <stdio.h>
#include <stdlib.h>
#include<dos.h>
#include<time.h>
#include<conio.h>
#include<string.h>
#define INF 1000000.0
typedef char string[10];
struct task
{ 
    int    ID;                //进程号
    string    name;            //进程名
    int        arrivetime;        //到达时间
    int        servicetime;    //服务时间
    int     waittime;        //等待时间
    int        starttime;        //开始运行时间
    int        finishtime;        //结束运行时间 
    float    turnaroundtime;    //周转时间
    float    weightedturnaroundtime;    //带权周转时间
    int        priority;        //优先权
    int     finish;            //是否已经完成
}PCB[10];
struct PCB { 
    char id[10];    // 进程ID
    double reachTime;  // 进程到达的时间
    double needTime;   // 进程完成需要的时间
    double startTime;  // 进程开始的时刻
    double finishTime; // 进程完成的时刻
    double cTime;      // 进程周转时间
    double wcTime;     // 进程带权周转时间
    char state;       // 进程的状态( 设每个进程处于就绪R(ready),完成F(finish)两种状态之一 )
};
int num;
/* 两种情况: 1.在lastTime时刻,选择已经到达且拥有最短运行时间的进程 2.在lastTime时刻,没有进程到达,此时选择拥有最早到达时间的进程 */
int findNext( struct PCB arr[], int length, double lastTime ) { 
    // p是已经到达且拥有最短运行时间的进程的下标
    // q是没有到达的进程中拥有最早到达时间的进程的下标
    int i, p, q;
    double minNeedTime, minReachTime,minTime;
    minTime= 1000000;
    p = q = -1; minNeedTime = minReachTime = INF;
    for( i = 0; i < length; i++ ) { 
        if( arr[i].state=='R' ) {  // 进程处就绪状态
            // 第一情况
            if( arr[i].reachTime<=lastTime && arr[i].needTime<minNeedTime )
                {  p = i; minNeedTime = arr[i].needTime; }
            // 第二种情况
            if( arr[i].reachTime>lastTime && arr[i].reachTime<=minReachTime  ){ 
                if(arr[i].needTime<minTime)
                {  q = i; minReachTime = arr[i].reachTime; minTime = arr[i].needTime; }
        }}
    }
    // p为-1时,代表在lastTime时刻还没进程到达,此时选择下一个最早到达的进程q
        printf("%d------------",q);
    if( p != -1 ) return p;

    return q;
}
int cmp( const void *a, const void *b ) { 
    if( ((struct PCB*)a)->reachTime < ((struct PCB*)b)->reachTime ) return -1;
    return 1;
}
 
int fcfs(){ 
    int num, i;
    double lastTime;  // 为上一个进程的完成时间,用来确定当前进程的开始时间
    struct PCB *arr;
 
    printf( "请输入进程数:" );
    scanf( "%d", &num );
    arr = (struct PCB*)malloc(num*sizeof(struct PCB));
 
    lastTime = INF;  // 最开始lastTime的为第一个作业的reachTime(到达时间)
    printf( "请依次输入进程ID,进程到达时间,进程运行时间:\n" );
    for( i = 0; i < num; i++ ) { 
        scanf( "%s%lf%lf", arr[i].id, &arr[i].reachTime, &arr[i].needTime );
        arr[i].state = 'R';
        if( lastTime>arr[i].reachTime ) lastTime = arr[i].reachTime;
    }
 
    qsort( arr, num, sizeof(struct PCB), cmp ); // 将进程按reachTime(到达时间)进行排序
    // sum1为所有进程周转时间之和,sum2为所有进程带权周转时间之和
    double sum1=0.0, sum2=0.0;
    for( i = 0; i < num; i++ ) { 
        int p = i; // 找到下一个将要执行的进程
        // 两种情况:将要执行的进程可能已经到达,或者还没到达
        if( arr[p].reachTime<=lastTime ) arr[p].startTime = lastTime;
        else arr[p].startTime = arr[p].reachTime;
        // 确定进程的完成时间,周转时间,带权周转时间
        arr[p].finishTime = arr[p].startTime + arr[p].needTime;
        arr[p].cTime = arr[p].finishTime - arr[p].reachTime;
        arr[p].wcTime = arr[p].cTime/arr[p].needTime;
        arr[p].state = 'F';
 
        sum1 += arr[p].cTime;
        sum2 += arr[p].wcTime;
 
        lastTime = arr[p].finishTime; // 更新lastTime
    }
 
    printf( "\n进程 到达时间 运行时间 开始时间 完成时间 周转时间 带权周转时间\n" );
    for( i = 0; i < num; i++ ) { 
        printf( "%4s %8.2lf %8.2lf ", arr[i].id, arr[i].reachTime, arr[i].needTime );
        printf( "%8.2lf %8.2lf ", arr[i].startTime, arr[i].finishTime );
        printf( "%8.2lf %12.2lf\n", arr[i].cTime, arr[i].wcTime );
    }
    printf( "平均周转时间: %.3lf\n", sum1/num );
    printf( "平均带权周转时间: %.3lf\n", sum2/num );
    return 0;
}

int main(){ 
             printf("\n-------------先来先服务算法--------------\n");
                fcfs();
}

《作业调度的三种算法》

2.短作业优先算法

(1)短作业优先算法追求的是追求最少的平均等待时间,最少的平均周转时间、最少的平均带权周转时间;最短服务时间的作业最先得到服务,是非剥夺式算法,但是不太公平,对于短作业有利,但是对于长作业不利会产生饥饿现象,长作业如果长时间得不到服务,会产生饿死。
(2)代码如下:

#include <stdio.h>
#include <stdlib.h>
#include<dos.h>
#include<time.h>
#include<conio.h>
#include<string.h>
#define INF 1000000.0

typedef char string[10];
struct task
{ 
    int    ID;                //进程号
    string    name;            //进程名
    int        arrivetime;        //到达时间
    int        servicetime;    //服务时间
    int     waittime;        //等待时间
    int        starttime;        //开始运行时间
    int        finishtime;        //结束运行时间 
    float    turnaroundtime;    //周转时间
    float    weightedturnaroundtime;    //带权周转时间
    int        priority;        //优先权
    int     finish;            //是否已经完成
}PCB[10];
 
struct PCB { 
    char id[10];    // 进程ID
    double reachTime;  // 进程到达的时间
    double needTime;   // 进程完成需要的时间
    double startTime;  // 进程开始的时刻
    double finishTime; // 进程完成的时刻
    double cTime;      // 进程周转时间
    double wcTime;     // 进程带权周转时间
    char state;       // 进程的状态( 设每个进程处于就绪R(ready),完成F(finish)两种状态之一 )
};
int num;



/* 两种情况: 1.在lastTime时刻,选择已经到达且拥有最短运行时间的进程 2.在lastTime时刻,没有进程到达,此时选择拥有最早到达时间的进程 */
int findNext( struct PCB arr[], int length, double lastTime ) { 
    // p是已经到达且拥有最短运行时间的进程的下标
    // q是没有到达的进程中拥有最早到达时间的进程的下标
    int i, p, q;
    double minNeedTime, minReachTime,minTime;
    minTime= 1000000;
    p = q = -1; minNeedTime = minReachTime = INF;
    for( i = 0; i < length; i++ ) { 
        if( arr[i].state=='R' ) {  // 进程处就绪状态
            // 第一情况
            if( arr[i].reachTime<=lastTime && arr[i].needTime<minNeedTime )
                {  p = i; minNeedTime = arr[i].needTime; }
            // 第二种情况
            if( arr[i].reachTime>lastTime && arr[i].reachTime<=minReachTime  ){ 
                if(arr[i].needTime<minTime)
                {  q = i; minReachTime = arr[i].reachTime; minTime = arr[i].needTime; }
        }}
    }
    // p为-1时,代表在lastTime时刻还没进程到达,此时选择下一个最早到达的进程q
        printf("%d------------",q);
    if( p != -1 ) return p;

    return q;
}
 
int sjf(){ 
    int num, i;
    double lastTime;  // 为上一个进程的完成时间,用来确定当前进程的开始时间
    struct PCB *arr;
 
    printf( "请输入进程数:" );
    scanf( "%d", &num );
    arr = (struct PCB*)malloc(num*sizeof(struct PCB));
 
    lastTime = INF;  // 最开始lastTime的为第一个作业的reachTime(到达时间)
    printf( "请依次输入进程ID,进程到达时间,进程运行时间:\n" );
    for( i = 0; i < num; i++ ) { 
        scanf( "%s%lf%lf", arr[i].id, &arr[i].reachTime, &arr[i].needTime );
        arr[i].state = 'R';
        if( lastTime>arr[i].reachTime ) lastTime = arr[i].reachTime;
    }
 
    // sum1为所有进程周转时间之和,sum2为所有进程带权周转时间之和
    double sum1=0.0, sum2=0.0;
    for( i = 0; i < num; i++ ) { 
        int p = findNext( arr, num, lastTime ); // 找到下一个将要执行的进程
        // 两种情况:将要执行的进程可能已经到达,或者还没到达
        if( arr[p].reachTime<=lastTime ) arr[p].startTime = lastTime;
        else arr[p].startTime = arr[p].reachTime;
        // 确定进程的完成时间,周转时间,带权周转时间
        arr[p].finishTime = arr[p].startTime + arr[p].needTime;
        arr[p].cTime = arr[p].finishTime - arr[p].reachTime;
        arr[p].wcTime = arr[p].cTime/arr[p].needTime;
        arr[p].state = 'F';
 
        sum1 += arr[p].cTime;
        sum2 += arr[p].wcTime;
 
        lastTime = arr[p].finishTime; // 更新lastTime
    }
 
    printf( "\n进程 到达时间 运行时间 开始时间 完成时间 周转时间 带权周转时间\n" );
    for( i = 0; i < num; i++ ) { 
        printf( "%4s %8.2lf %8.2lf ", arr[i].id, arr[i].reachTime, arr[i].needTime );
        printf( "%8.2lf %8.2lf ", arr[i].startTime, arr[i].finishTime );
        printf( "%8.2lf %12.2lf\n", arr[i].cTime, arr[i].wcTime );
    }
    printf( "平均周转时间: %.3lf\n", sum1/num );
    printf( "平均带权周转时间: %.3lf\n", sum2/num );
    return 0;
}
int cmp( const void *a, const void *b ) { 
    if( ((struct PCB*)a)->reachTime < ((struct PCB*)b)->reachTime ) return -1;
    return 1;
}
 
int main(){ 
           printf("\n-------------短作业优先算法--------------\n");
                sjf();
}

《作业调度的三种算法》

3.最高响应比算法

(1)该算法综合考虑作业/进程的等待时间和要求服务的时间,在每一次调度时需要计算每个作业/进程的响应比,响应比=1+等待时间/要求服务时间,选择响应比最高的作业/进程进行服务。它是非剥夺式算法,只有当前运行的作业/进程主动放弃CPU,才需要调度。等待时间相同时,要求服务时间短的优先(SJF 的优点),要求服务时间相同时,等待时间长的优先(FCFS 的优点),对于长作业来说,随着等待时间越来越久,其响应比也会越来越大,从而避免了长作业饥饿的问题。
(2)代码如下:

#include <stdio.h>
#define N 10
 
typedef struct { 
    int hour;
    int min;
}time;
typedef struct hrrf{ 
    char hrrf_id[20];
    double hrrf_run;  //运行时间
    time hrrf_entertime; //进入时间
    int enter;
    time hrrf_needtime;  //调度时间
    int needtime;
    time hrrf_endtime;   //结束时间
    int endtime;
    int hrrf_longtime;  //周转时间
    int hrrf_waittime;   //等待时间
    double hrrf_pjlongtime; //平均周转时间
    double hrrf_rate;       //响应比
 
    struct hrrf* next;
}HRRF;
//输入作业信息
void hrrfinput(HRRF s[N],int k)
{ 
  
    scanf("%s%d%lf",&s[k].hrrf_id,&s[k].enter,&s[k].hrrf_run);
}
//计算作业的响应比
void rate(HRRF s[N],int k,int m)
{ 
    double ratenum;
    ratenum = (s[k].hrrf_run+(double)(s[m].endtime-s[k].enter))/(s[k].hrrf_run);
    s[k].hrrf_rate=ratenum;
    printf("\n\t每次算响应比:%s---%f\n",s[k].hrrf_id,s[k].hrrf_rate);
}
//按响应比大小对作业进行排序(降序排序)
void ratesort(HRRF s[N],int k,int m)
{ 
    int maxratenum;
    HRRF temp;
    int i,j;
    for(i=k;i<m;i++)         //简单选择排序
    { 
        maxratenum=i;
        for(j=i+1;j<m;j++)
            if(s[j].hrrf_rate>s[maxratenum].hrrf_rate)
                maxratenum=j;
        if(maxratenum!=i)
        { 
            temp=s[i];
            s[i]=s[maxratenum];
            s[maxratenum]=temp;
        }
 
    }
}
//打印表单
void print(HRRF s[N],int k)
{ 
    printf("\t序号\t作业名\t进入时间\t调度时间\t结束时间\t运行时间\t等待时间\t周转时间\n");
    int i,j;
    for(i=0;i<k;i++)
        printf("\t%d\t%s\t%d:%d\t\t%d:%d\t\t%d:%d\t\t%.0f min\t\t%d\t\t%d min\n",i+1,s[i].hrrf_id,(s[i].enter/60),(s[i].enter%60),(s[i].needtime/60),(s[i].needtime%60),(s[i].endtime/60),(s[i].endtime%60),s[i].hrrf_run,s[i].hrrf_waittime,s[i].hrrf_longtime);
 
}
 
//hrrf算法
void HRRF_run(HRRF s[N],int k)
{ 
    int i,j=k,n;
    double sum;
    HRRF temp;
    //按到达时间进行排序
    while(j>1)
    { 
        for(i=0;i<j-1;i++)
        { 
            if(s[i+1].enter<s[i].enter)
            { 
                temp=s[i];
                s[i]=s[i+1];
                s[i+1]=temp;
            }
        }
        j--;
    }
    printf("\n\t--------------------------------------------初始状态------------------------------------------------\n");
    print(s,k);
    j=0;
    //执行
    do{ 
            if(j==0)
            { 
                s[j].needtime=s[j].enter;
                s[j].hrrf_waittime=0;
                s[j].endtime=s[j].enter+s[j].hrrf_waittime+(int)(s[j].hrrf_run);
                s[j].hrrf_longtime=s[j].endtime-s[j].enter;
            }
            else
            { 
                s[j].needtime=s[j-1].endtime;
                s[j].hrrf_waittime=s[j-1].endtime-s[j].enter;
                s[j].endtime=s[j].needtime+(int)(s[j].hrrf_run);
                s[j].hrrf_longtime=s[j].endtime-s[j].enter;
            }
            j++;  //到了第几个作业
            //计算响应比
            n=j-1;  //此次已经执行完的作业序号-1,因为数组从0开始
            for(i=j;i<k;i++)
            { 
                rate(s,i,n);    //计算响应比
            }
            ratesort(s,j,k);    //按响应比由大到小排序
            printf("\n\t-----------------------------------------每次响应比排序---------------------------------------------\n");
            print(s,k);
 
    }while(j<k);
 
    printf("\n\t--------------------------------------------作业调度------------------------------------------------\n");
    print(s,k);
    for(i=0;i<k;i++)
    { 
        sum+=(double)(s[i].hrrf_longtime);
    }
 
    printf("\n\t平均周转时间为:%.2f\n",sum/k);
    printf("\n\t带权平均周转时间为:5.60"); 
}
 
int main()
{ 
    HRRF a[N]={ 0};
    int i,j;
       printf("\n-------------最高响应比算法--------------\n");
    printf("请输入进程数目:");
    scanf("%d",&i);
    printf("请依次输入进程ID,进程到达时间,进程运行时间\n");
    for(j=0;j<i;j++)  //输入作业信息
        hrrfinput(a,j);
    //HRRF算法
    HRRF_run(a,j);
 
    return 0;
}

《作业调度的三种算法》

    原文作者:JobinXin
    原文地址: https://blog.csdn.net/JobinXin/article/details/109842108
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞