操作系統——進程調度之短進程優先


 1、什么是進程調度

  無論是在批處理系統還是分時系統中,用戶進程數一般都多於處理機數、這將導致它們互相爭奪處理機。另外,系統進程也同樣需要使用處理機。這就要求進程調度程序按一定的策略,動態地把處理機分配給處於就緒隊列中的某一個進程,以使之執行。   

 

2、處理機調度分類

高級、中級和低級調度作業從提交開始直到完成,往往要經歷下述三級調度:
  • 高級調度:(High-Level Scheduling)又稱為作業調度,它決定把后備進程調入內存運行; 
  • 低級調度:(Low-Level Scheduling)又稱為進程調度,它決定把就緒隊列的某進程獲得CPU; 
  • 中級調度:(Intermediate-Level Scheduling)又稱為在虛擬存儲器中引入,在內、外存對換區進行進程對換

3、短進程優先

最短CPU運行期優先調度算法(SCBF--Shortest CPU Burst First)
該算法 從就緒隊列中選出下一個“CPU執行期最短”的進程,為之分配處理機
例如,在就緒隊列中有四個進程P1、P2、P3和P4,它們的下一個執行
期分別是16、12、4和3個單位時間,執行情況如下圖:
P1、P2、P3和P4的周轉時間分別為35、19、7、3,平均周轉時間為16。
該算法雖可獲得較好的調度性能,但難以准確地知道下一個CPU執行期,而只能根據每一個進程的執行歷史來預測。
 
4、C語言模式實現
  1》、常量聲明和數據結構定義
#include "stdio.h"
#include <stdlib.h>
#include "string.h"
#define NULL 0

typedef struct pcb
{
    char name[10]; //進程名稱
    int ArrivalTime; //到達時間 
    int StartTime;   //開始運行時間
    int FinishTime;  //結束運行時間
    int WholeTime;   //運行所需時間

    struct pcb *link; //下一個指針 
}pcb; 
int N;  //運行的進程數量 
void input();
pcb *ready=NULL,*p=NULL,*finish = NULL;  
//ready 是初始時的狀態,finish 是結束時狀態 
int M; 

 

  2》、輸入進程信息函數
void input()
{
    printf("請輸入進程數量:");
    scanf("%d",&N);   //N為全局變量
    M = N;
    struct pcb *q = ready;
    int  i = 0;
    for( i=0 ;i<N;i++)
    {
        printf("請輸入第 %d 個進程信息-----------\n",i+1);
        p = (pcb *)malloc(sizeof(pcb));
        printf("請輸入進程名:")    ;
        scanf("%s",p->name);
        printf("請輸入進程到達時間:");
        scanf("%d",&p->ArrivalTime);
        printf("請輸入進程運行時間:");
        scanf("%d",&p->WholeTime);
        p->link = NULL;
        if(NULL == ready)
        {
            ready = p;    
            q = ready;        
        }
        else
        {
            q = ready;
            while(NULL != q->link)  //將q移動到就緒隊列最后一個進程 
            {
                q = q->link;
            }
            p->link = NULL;
            q->link = p;    
            q=p;
        }
        printf("\n");
    }
    q= NULL;
    free(q);    
} 

 

  3》、短進程優先算法【核心代碼】
//先輸入的肯定是先到達的 
//nowTime 是現在執行的時間 
pcb* sjf(int nowTime,int *after)
{
    int i = 0 ;
    pcb *nowProgress=NULL, *p = ready;
    int ProgressNum = 0; // 當前最短的是第幾個線程 
    int minTime =0; // 最短運行時間
    
    if(NULL != ready)
    {
        while(NULL != p) //遍歷整個鏈表,查找出最短的進程,即運行時間最短 
        {
        //    printf("\n%d  %d  %d  \n",p->ArrivalTime,nowTime >= p->ArrivalTime,nowTime) ;
            if(nowTime >= p->ArrivalTime)
            { 
                if(0 == minTime)  //首次賦值 
                {
                    nowProgress = p;
                    minTime = p->WholeTime;                    
                }
                else
                {
                    if(p->WholeTime < minTime)
                    {
                        nowProgress = p;
                        minTime = p->WholeTime;
                    }
                }
                
                *after = minTime+nowTime;
            }    
            p = p->link;
        }
    } 
    
    return nowProgress;    
}

 

  4》、輸出每個時刻的進程信息函數
void output(pcb *p,int now_time)
{
    if(NULL == p)
    {
        printf("當前時刻:%d,暫無進程在運行!\n",now_time);
    }
    else
    {
            printf("進程名:%s,運行時間:%d,到達時間:%d\n",p->name,p->WholeTime,p->ArrivalTime);        
    }    
}

 

  5》、輸出進程運行總體情況統計

void outputAll()
{
    pcb *p = finish;
    printf("\n-----------------------統計結果:-------------------\n");
    float avgRevolve = 0;
    float avgSuperRevolve = 0;
     
    while(NULL != p)
    {
        avgRevolve += p->StartTime+p->WholeTime-p->ArrivalTime;
        avgSuperRevolve += 1.0*(p->StartTime+p->WholeTime-p->ArrivalTime)/p->WholeTime;
        printf("\n進程名:%s,開始時間%d,結束時間:%d,運行時間:%d,到達時間:%d\n",p->name,p->StartTime,p->FinishTime,p->WholeTime,p->ArrivalTime);
        p = p->link;    
    }    
        printf("\n----這組進程平均周轉時間:%f,平均帶權平均周轉時間:%f\n",avgRevolve/M,avgSuperRevolve/M);
} 

   

  6》、刪除准備隊列(ready)已經運行的進程p ,添加到完成隊列(finish)隊列中 

// 刪除准備隊列(ready)已經運行的進程p ,添加到完成隊列(finish)隊列中 
void destory(pcb *p,int now_time)
{

    pcb *q = ready;
    pcb *f = NULL;
    if(strcmp(p->name,ready->name) == 0)  //第一個進程 
    {
        ready = ready ->link;
    }
    else  //中間進程 
    {
        q = ready;

        while(  (strcmp(q->link->name,p->name) != 0) && NULL != q->link)  //找到p要刪除的位置 
        {
            
            q= q->link;
                
        }
    
        q->link = p->link;    
    
        
    
    } 
    
    
    
    
        //將已經運行的進程添加到finish隊列 
        p->StartTime = now_time-p->WholeTime;   
        p->FinishTime = now_time;
    
        if(NULL == finish)  //第一個完成的進程 
        {
            finish = p;
            p->link = NULL;
        }    
        else  //中間完成的進程 
        {
            f = finish;
            while(NULL != f->link )    
            {
                f = f->link;
            }
            f->link = p;
            p->link = NULL;
        }
    
    

    
    N--;  //等待進程減1 
}

 

  7》、主函數
int main()
{

    input();

    struct pcb *s = ready;  
    int now_time = 0 ;
    struct pcb *nowProgress = NULL;  //當前運行的進程 
    int *after = 0; //執行完一個進程之后的時間 
    int i = 0 ;   
    
    pcb *m = ready;
    
    while(N > 0)//一次運行一個進程 
    {
        nowProgress = sjf(now_time,&after);
        
        if(NULL != nowProgress)  //當前有進程在運行 
        {
    
        for(;now_time < after;now_time++)  //輸出每個時刻運行的進程情況 
        {
            printf("#################################################\n");
            printf("當前時刻:%d\n",now_time);
             printf("\n-------------當前執行進程:----------\n"); 
                 output(nowProgress,now_time);
                 printf("\n-------------等待執行進程:----------\n");
            m=ready;
            while(NULL != m)
            {
                if(m != nowProgress)
                {
                    if(m->ArrivalTime <= now_time)
                    output(m,now_time);
                }
                m= m->link;
            }
            printf("#################################################\n\n");
        }
                    
            printf("\n");

            destory(nowProgress,now_time); 
            
        }
        else   //沒有進程在運行 
        {
            output(nowProgress,now_time);
            now_time ++; 
        }
                
    }            
    outputAll();
    return 0;
}

 

  8》、測試
輸入數據:
 
運行結果:
 
省略中途的截圖,這里只給出最后的總計情況的截圖
 
 
  實際上,進程調度有很多種進程調度的方式,不同的進程調度方式,他們的優缺點各有不同,而且他們的適用場景也不盡相同,這里只給出了短進程優先的調度方式。下面我們來比較一下,一些調度方式【只是部分】的優缺點:

1.先來先服務(FCFS, First Come First Serve),按先后順序進行調度。 
(1)、適用場景:
比較有利於長進程,而不利於短進程。因為長進程會長時間占據處理機。
有利於CPU繁忙的進程,而不利於I/O繁忙的進程。 

(2)、優點:

有利於長進程,有利於等待時間久的進程,不會有進程長期等待而得不到響應。有利於CPU頻繁的進程。

(3)、缺點:

不利於短進程,忽視了進程的運行時間。不利於I/O頻繁的進程。

 

 

2. 響應比高者優先(HRN):FCFS和SJF的的折中,動態生成昨夜的優先級。

(1)、優點:

既考慮了進程的等待時間,又考慮了進程的運行時間,是FCFS和SJF的的折中,會考慮讓進程短的先進行,隨着長進程等待時間的增加,優先級相應的增加,使得通過一定時間的等待,必然有機會獲得處理機。

(2)、缺點:

在每次進行調度之前,都需要先做響應比的計算,會增加系統的開銷


3. 優先級法(Priority Scheduling):按照進程的優先級,對進程進程調度。

(1)、分類:
靜態優先級:
  進程調度中的靜態優先級大多按以下原則確定: 
  由用戶自己根據進程的緊急程度輸入一個適當的優先級。 
  由系統或操作員根據進程類型指定優先級。 
  系統根據進程要求資源情況確定優先級。 
  進程的靜態優先級的確定原則: 
  按進程的類型給予不同的優先級。 
  將進程的情態優先級作為它所屬進程的優先級。 
動態優先級:
  進程的動態優先級一般根據以下原則確定: 
  根據進程占用有CPU時間的長短來決定。 
  根據就緒進程等待CPU的時間長短來決定。 

(2)、優點:

可以通過優先級反映進程的緊迫程序,使比較緊迫的進程優先運行

(3)、缺點:

需要計算進程的優先級,會產生一定的開銷。
4.短進程優先法(SJF, Shortest Job First):短進程優先運行,其目標是減少平均周轉時間。 

(1) 優點: 
  比FCFS改善平均周轉時間和平均帶權周轉時間,縮短進程的等待時間; 
  提高系統的吞吐量; 
(2) 缺點: 
  對長進程非常不利,可能長時間得不到執行; 
  未能依據進程的緊迫程度來划分執行的優先級; 
  難以准確估計進程(進程)的執行時間,從而影響調度性能。 

采用SJF算法時,人—機交互無法實現

 完全未考慮進程的緊迫程度,故不能保證緊迫性進程得到及時處理

 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM