一、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指針了。
總代碼

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; 26 27 28 //用來測試鏈表建立,輸入鏈表結構體數據 29 void print_test(){ 30 int i; 31 struct pcb * test = ready; 32 for(i=0;i<num;i++){ 33 printf("\n進程號:%d,進程名:%s,進程到達時間:%d,進程完成時間:%d", 34 i,test->name,test->arrival_time,test->need_time); 35 if(NULL != test->link){ 36 test = test->link; 37 } 38 else{ 39 printf("\ntest_link end\n"); 40 } 41 42 } 43 } 44 45 46 47 //輸入函數,建立鏈表 48 void input(){ 49 int i; 50 struct pcb * q; //定義結構體變量 51 printf("請輸入進程數:"); 52 scanf("%d", &num); 53 for(i=0; i<num; i++){ 54 printf("\n進程號 NO.%d:", i); 55 p = (struct pcb*)malloc(sizeof(struct pcb)); 56 printf("\n輸入進程名:"); 57 scanf("%s", p->name); 58 printf("\n請輸入進程到達時間:"); 59 scanf("%d", &p->arrival_time); 60 printf("\n請輸入進程運行時間:"); 61 scanf("%d", &p->need_time); 62 63 p->link = NULL; 64 //建立鏈表 65 if(NULL == ready){ //建立第一個結構體,使指針p,q指向它 66 ready = p; 67 q = ready; 68 } 69 else{ //鏈表建立 70 q->link = p; 71 q = p; 72 } 73 printf("input success"); 74 } 75 print_test(); //測試鏈表是否建立 76 } 77 78 79 80 //sjf shortest job first最短作業優先 81 struct pcb * SJF(int now_time, int * after){ 82 int min_time = 0; //最短時間,即優先運行的進程的時間 83 struct pcb * now_progress = NULL, *p = ready; 84 //遍歷鏈表,查找出運行時間最短的進程 85 if (NULL != ready){ 86 while(NULL != p){ 87 if(now_time >= p->arrival_time){ //若進程已經到達,注意:時間單位為1 88 /* 89 min_time = p->need_time; //是錯誤的 90 now_progress = p; 91 if(p->need_time < min_time){ 92 min_time = p->need_time; 93 now_progress = p; 94 } */ 95 if(0 == min_time){ //給最短時間賦初值 96 now_progress = p; 97 min_time = p->need_time; 98 } 99 else{ 100 if(p->need_time < min_time){ 101 now_progress = p; 102 min_time = p->need_time; 103 } 104 } 105 } 106 p = p->link; 107 } 108 } 109 *after = min_time + now_time; 110 printf("\nSJF:a shortest progress running!\n"); 111 return now_progress; //返回指向正在運行進程的指針 112 } 113 114 115 //輸出當前運行進程相關數據或者打印暫無進程運行 116 void output(struct pcb * p, int now_time){ 117 if(NULL == p){ 118 printf("當前時刻:%d, 暫無進程在運行!\n", now_time); 119 } 120 else{ 121 printf("進程名:%s,到達時間:%d,運行需要時間:%d\n",p->name,p->arrival_time,p->need_time); 122 } 123 } 124 125 126 //將已經運行完成的進程添加到finish隊列,並且進程數減一 127 void destory(struct pcb * p, int now_time){ 128 printf("destory start!\n"); 129 struct pcb * q = ready; 130 struct pcb * f = NULL; //用於finish鏈表的添加 131 132 133 if(strcmp(p->name, ready->name) == 0){ //若第一個進程完成 134 ready = ready->link; 135 } 136 //若中間或最后一個進程完成 137 else{ 138 q = ready; 139 while((strcmp(q->link->name,p->name) != 0) && NULL != q->link){ 140 q = q->link; 141 } 142 q->link = p->link; 143 } 144 145 p->finish_time = now_time; //結束時間 146 p->start_time = now_time - p->need_time; //開始時間 147 148 //將已經運行的進程添加到finish隊列 149 if(NULL == finish){ 150 finish = p; //finish指向完成鏈表的表頭 151 p->link = NULL; 152 } 153 else{ 154 f = finish; 155 while(NULL != f->link){ 156 f = f->link; 157 } 158 f->link = p; 159 p->link = NULL; 160 } 161 162 num--; //進程數減一 163 printf("\ndestory success!\n"); 164 } 165 166 167 168 void output_all(){ 169 struct pcb * p = finish; 170 printf("\n---------------統計結果----------------\n"); 171 while(NULL != p){ 172 printf("\n進程名:%s,開始時間:%d,結束時間:%d,運行時間:%d,到達時間:%d", 173 p->name,p->start_time,p->finish_time,p->need_time,p->arrival_time); 174 p = p->link; 175 } 176 } 177 178 179 180 int main(int argc, char *argv[]) { 181 182 183 input(); //調用輸入函數 184 185 int now_time = 0; //初始時間為0 186 int after = 0; //執行完一個進程后的時間:優先運行進程的運行時間+當前時間 187 struct pcb * now_progress = NULL; //now_progress指向正在運行的進程(結構體) 188 struct pcb *m = NULL; 189 190 while(num > 0){ //進程數大於0,每次循環num會減一 191 printf("start SJF"); 192 now_progress = SJF(now_time, &after); //調用SJF函數,遍歷鏈表 193 194 195 if(NULL != now_progress){ 196 /*進程執行,每循環一次,當前時間加一 197 同時要判斷當前時間是否有進程剛好到達正在在等待 */ 198 for(;now_time < after; now_time++){ 199 printf("\n當前時刻:%d", now_time); 200 printf("\n-----------當前執行進程------------\n"); 201 output(now_progress, now_time); //調用output函數 202 printf("\n-----------等待執行進程------------\n"); 203 204 m = ready; 205 while(NULL != m){ //循環,若當前時間有進程到達,打印相關信息 206 if(m != now_progress){ 207 if(m->arrival_time <= now_time){ 208 output(m, now_time); 209 printf("\na new progress arrival\n"); 210 } 211 } 212 m = m->link; 213 } 214 } 215 //進程執行完后調用destory函數 216 destory(now_progress, now_time); 217 218 } 219 else{ //沒有進程在運行 220 output(now_progress, now_time); 221 now_time++; 222 } 223 224 } 225 output_all(); 226 return 0; 227 228 }