一、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;
我又回去看前面的代碼,改正如下:
運行結果:
六、總結知識點
p = (struct pcb*)malloc(sizeof(struct pcb))與p = (struct pcb*)malloc(sizeof(PCB))相同, PCB是結構體struct pcb的一個結構體變量。
在使用字符串處理函數(puts,gets,strcat,strcpy,strcmp,strlen,strlwr)時,應當在程序文件的開頭用#include<string.h>,把"string.h"文件包含到本文件中。
malloc函數。比如:malloc(100) 開闢100字節的臨時分配域,函數值爲其第1個字節的地址。只提供一個地址。若函數不能成功執行(比如內存不足),則返回空指針。(int*)malloc(sizeof(int)) 將申請得到的空間地址轉換成了int類型空間地址最後就可以賦值給指向int型空間的p指針了。