短進程優先的調度算法詳解

一、SPF算法簡介

SJF算法

  • SJF(shortest job first)是以進程的運行時間長度作爲優先級,進程運行時間越短,優先級越高。

SJF算法的缺點

  • 必須預知進程的運行時間。即使是程序員也很難準確估計進程運行時間。如果估計過低,系統就可能按估計的時間終止進程的運行,但此時進程並未完成,故一般都會偏長估計

  • 對長進程不利。長進程的週轉時間會明顯地增長。可怕的是,SJF算法完全忽視進程等待時間,可能使進程等待時間過長,出現飢餓現象。

  • 人機無法實現交互。

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

  

                         

二、算法流程圖

 我做的流程圖:http://www.processon.com/diagraming/5835692de4b086d1e79f81af

 

 

三、源代碼

1. 變量聲明與結構體定義

複製代碼

 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4  5 /* run this program using the console pauser or add your own getch, system("pause") or input loop */ 6  7  8 struct pcb{ 9     char name[10];    //進程名 10     int arrival_time; //進程到達時間() 11     int start_time;   //進程開始時間 12     int need_time;      //進程運行所需時間 13     int finish_time;  //運行結束時間 14     struct pcb * link;   //鏈接下一個pcb的指針 15 };16 17 18 int num = 0;     //輸入的進程數 19 typedef struct pcb PCB;    //定義結構體變量 20 /*21 結構體指針p指向 每新建的一個進程22 ready指針指向鏈表的第一個pcb 
23 finish指針指向完成隊列的第一個pcb結構體 
24 */25 struct pcb *p = NULL, *ready = NULL, *finish = NULL;

複製代碼

 

 

2. 輸入函數

複製代碼

 1 //用來測試鏈表建立,輸入鏈表結構體數據  2 void print_test(){ 3     int i; 4     struct pcb * test = ready; 5     for(i=0;i<num;i++){ 6         printf("\n進程號:%d,進程名:%s,進程到達時間:%d,進程完成時間:%d", 7                 i,test->name,test->arrival_time,test->need_time); 8         if(NULL != test->link){ 9             test = test->link;10         }11         else{12             printf("\ntest_link end\n");13         }14         15     }16 }17 18 19 20 //輸入函數,建立鏈表 21 void input(){22     int i;23     struct pcb * q;   //定義結構體變量 24     printf("請輸入進程數:");25     scanf("%d", &num);26     for(i=0; i<num; i++){27         printf("\n進程號 NO.%d:", i);28         p = (struct pcb*)malloc(sizeof(struct pcb));29         printf("\n輸入進程名:");30         scanf("%s", p->name);31         printf("\n請輸入進程到達時間:");32         scanf("%d", &p->arrival_time);33         printf("\n請輸入進程運行時間:");34         scanf("%d", &p->need_time);35         36         p->link = NULL;37         //建立鏈表38         if(NULL == ready){   //建立第一個結構體,使指針p,q指向它 39             ready = p;40             q = ready;41         } 
42         else{      //鏈表建立 43             q->link = p;44             q = p;    
45         }46         printf("input success");47     }48     print_test();   //測試鏈表是否建立 49 }

複製代碼

 

 

3.  所有進程結束後,輸出所有進程信息

複製代碼

1 //輸出當前運行進程相關數據或者打印暫無進程運行 2 void output(struct pcb * p, int now_time){3     if(NULL == p){4         printf("當前時刻:%d, 暫無進程在運行!\n", now_time);5     }6     else{7         printf("進程名:%s,到達時間:%d,運行需要時間:%d\n",p->name,p->arrival_time,p->need_time);8     }9 }

複製代碼

 

 

4.  找出運行時間最短的進程

複製代碼

 1 //sjf  shortest job first最短作業優先  2 struct pcb * SJF(int now_time, int * after){ 3     int min_time = 0;   //最短時間,即優先運行的進程的時間  4     struct pcb * now_progress = NULL, *p = ready; 5     //遍歷鏈表,查找出運行時間最短的進程  6     if (NULL != ready){ 7         while(NULL != p){ 8             if(now_time >= p->arrival_time){   //若進程已經到達,注意:時間單位爲1  9                 /*10                 min_time = p->need_time;      //是錯誤的 
11                 now_progress = p;12                 if(p->need_time < min_time){13                     min_time = p->need_time;14                     now_progress = p;15                 } */16                 if(0 == min_time){  //給最短時間賦初值17                     now_progress = p;18                     min_time = p->need_time;                    
19                 }20                 else{21                     if(p->need_time < min_time){22                         now_progress = p;23                         min_time = p->need_time;24                     }25                 }26             }27             p = p->link;28         }29     }30     *after = min_time + now_time;31     printf("\nSJF:a shortest progress running!\n");32     return now_progress;   //返回指向正在運行進程的指針 33 }

複製代碼

 

 

4. 進程執行完畢

複製代碼

 1 //將已經運行完成的進程添加到finish隊列,並且進程數減一  2 void destory(struct pcb * p, int now_time){ 3     printf("destory start!\n"); 
 4     struct pcb * q = ready; 5     struct pcb * f = NULL;   //用於finish鏈表的添加  6  7      8     if(strcmp(p->name, ready->name) == 0){  //若第一個進程完成  9         ready = ready->link;10     }11     //若中間或最後一個進程完成 12     else{13         q = ready;14         while((strcmp(q->link->name,p->name) != 0) && NULL != q->link){15             q = q->link;16         }17         q->link = p->link;18     }19     20      p->finish_time = now_time;    //結束時間21      p->start_time =  now_time - p->need_time;  //開始時間 
22      23     //將已經運行的進程添加到finish隊列24     if(NULL == finish){25         finish = p;    //finish指向完成鏈表的表頭 26         p->link = NULL;27     }28     else{29         f = finish;30         while(NULL != f->link){31             f = f->link;32         }33         f->link = p;34         p->link = NULL;35     }36     37     num--;   //進程數減一 38     printf("\ndestory success!\n");39 }

複製代碼

 

 

5. 主函數

複製代碼

 1 int main(int argc, char *argv[]) { 2      3      4     input();  //調用輸入函數  5      6     int now_time = 0;    //初始時間爲0  7     int after = 0;        //執行完一個進程後的時間:優先運行進程的運行時間+當前時間  8     struct pcb * now_progress = NULL;    //now_progress指向正在運行的進程(結構體)  9     struct pcb *m = NULL;10     11     while(num > 0){    //進程數大於0,每次循環num會減一 12         printf("start SJF");13         now_progress = SJF(now_time, &after);  //調用SJF函數,遍歷鏈表 14 15         16         if(NULL != now_progress){17             /*進程執行,每循環一次,當前時間加一18               同時要判斷當前時間是否有進程剛好到達正在在等待 */19             for(;now_time < after; now_time++){20                 printf("\n當前時刻:%d", now_time);21                 printf("\n-----------當前執行進程------------\n");22                 output(now_progress, now_time);     //調用output函數 23                 printf("\n-----------等待執行進程------------\n");24                 25                 m = ready;26                 while(NULL != m){   //循環,若當前時間有進程到達,打印相關信息 27                     if(m != now_progress){28                         if(m->arrival_time <= now_time){29                             output(m, now_time);30                             printf("\na new progress arrival\n");31                         }32                     }33                     m = m->link;34                 }35             }36             //進程執行完後調用destory函數 37             destory(now_progress, now_time);38 39         }40         else{   //沒有進程在運行 41             output(now_progress, now_time);42             now_time++;43         }44         45     }46     output_all();47     return 0;48     49 }

複製代碼

 

 我寫得這麼清楚,加上我畫的流程圖,相信你可以懂的~~

四、測試

 

 

 

 

五、坑

原本這個函數我是這樣寫的,但發現運行結果不對~

 按上面代碼的運行結果:

 

按理說,a進程執行後不應該是e進程執行,應該是運行時間最短的d進程執行。同理之後是b, e, c;

我又回去看前面的代碼,改正如下:

運行結果:

 

 

六、總結知識點

 

  1. p = (struct pcb*)malloc(sizeof(struct pcb))與p = (struct pcb*)malloc(sizeof(PCB))相同, PCB是結構體struct pcb的一個結構體變量。

  2. 在使用字符串處理函數(puts,gets,strcat,strcpy,strcmp,strlen,strlwr)時,應當在程序文件的開頭用#include<string.h>,把"string.h"文件包含到本文件中。

  3. malloc函數。比如:malloc(100) 開闢100字節的臨時分配域,函數值爲其第1個字節的地址。只提供一個地址。若函數不能成功執行(比如內存不足),則返回空指針。(int*)malloc(sizeof(int)) 將申請得到的空間地址轉換成了int類型空間地址最後就可以賦值給指向int型空間的p指針了。

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章