程序設計
一、數據結構
1.1 事件類型
由於要求是基於事件的進程調度,所以必須創建一個存放事件的隊列。
enum EventType{ ARRIVALEVENT, FINISHEVENT, TIMEREVENT }; //事件類型
1.2 任務結構(每一項數據都是輸入):
struct Job { char name[50]; //作業名 int arriveTime; //作業到達時間 int needTime; //作業所需運行時間 int priority; //作業優先級,數字越小,優先級越高 };
1.3 事件鏈表結點:
struct Event { EventType type; //事件類型 int jobBeginTime; //作業開始時間 bool isFirstExe; //判斷是否第一次執行,用於記錄作業開始時間 int happenTime; //發生時刻 int remainTime; //剩余運行時間 double hrr; //最高響應比 Job job; //作業 Event *next; //事件指針 };
因為事件為隊列存儲,因而需要動態增刪,所以較佳的數據結構是鏈表。因為是鏈表,所以要定義一套操作鏈表的函數。
二、程序流程圖
2.1 非搶占式調度
2.2 搶占式調度
2.3 輪轉調度
三、過程定義
3.1 事件隊列相關函數
/* 作業復制函數 */ void CopyJob( Job *dest, const Job *sour ); /* 事件隊列創建函數 * 包含頭節點 * 返回頭指針 */ Event *CreateEventQueue(); /* 抓取頭結點之外的第一個事件 * 作為返回值返回 */ Event *FetchFirstEvent( Event *head ); /* 如果值相同,時間將插在前方 */ void InsertFinishEvent( Event *head, Event *e ); /* 插入到隊尾 */ void InsertTail( Event *head, Event *e ); /* 按作業名稱刪除第一個匹配項, * 刪除成功返回TRUE,不存在該節點返回FALSE */ bool DeleteByJobName( Event *head, char *jobName ); /* 刪除事件隊列 */ void DestroyQueue( Event *head );
3.2 進程調度相關函數
/* 插入函數 */ void InsertByHappenTime( Event *head, Event *e ); void InsertByJobTime( Event *head, Event *e ); void InsertByPriority( Event *head, Event *e ); void InsertByRemainTime( Event *head, Event *e ); void InsertByHRR( Event *head, Event *e ); /* 排序函數 */ void SortByHRR( Event *head, int currentTime ); /* 調度函數 */ void SJF ( Event *eventHead ); void SRTF( Event *eventHead ); void HRRF( Event *eventHead ); void Priority(Event *eventHead); //搶占式優先級調度 void RR ( Event *eventHead ); //時間片大小為1
程序實現
一、插入函數(用於插入排序)
1.1 按開始時間插入
void InsertByHappenTime( Event *head, Event *e ) { if ( head == NULL || e == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } Event *p = head; while ( ( p->next != NULL ) && ( e->happenTime >= (p->next)->happenTime ) ) { p = p->next; } e->next = p->next; p->next = e; }
1.2 按結束時間插入
void InsertFinishEvent( Event *head, Event *e ) { if ( head == NULL || e == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } Event *p = head; while ( ( p->next != NULL ) && ( e->happenTime > (p->next)->happenTime ) ) { p = p->next; } e->next = p->next; p->next = e; }
1.3 按作業時間插入
void InsertByJobTime( Event *head, Event *e ) { if ( head == NULL || e == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } Event *p = head; while ( ( p->next != NULL ) && ( (e->job).needTime >= (p->next)->job.needTime ) ) { p = p->next; } e->next = p->next; p->next = e; }
1.4 按剩余時間插入
void InsertByRemainTime( Event *head, Event *e ) { if ( head == NULL || e == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } Event *p = head; while ( ( p->next != NULL ) && ( e->remainTime >= p->next->remainTime ) ) { p = p->next; } e->next = p->next; p->next = e; }
1.5 按優先級插入
void InsertByPriority( Event *head, Event *e ) { if ( head == NULL || e == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } Event *p = head; while ( ( p->next != NULL ) && ( e->job.priority >= p->next->job.priority ) ) { p = p->next; } e->next = p->next; p->next = e; }
1.6 按最高響應比插入
void InsertByHRR( Event *head, Event *e ) { if ( head == NULL || e == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } Event *p = head; while ( ( p->next != NULL ) && ( e->hrr <= p->next->hrr ) ) { p = p->next; } e->next = p->next; p->next = e; }
1.7 最高響應比插入排序
void SortByHRR( Event *head, int currentTime ) { Event *addrValue = new Event; addrValue->next = head->next; Event *p = addrValue->next; head->next = NULL; //將節點放置另一個鏈表中 while ( p != NULL ) { p->happenTime = currentTime; p->hrr = 1 + ( p->happenTime - p->job.arriveTime ) / p->job.needTime * 0.1; p = p->next; } while ( p = FetchFirstEvent( addrValue ) ) { InsertByHRR( head, p ); p = addrValue->next; } delete addrValue; addrValue = NULL; }
二、調度算法
2.1 最短工作時間優先
void SJF( Event *eventHead ) { if ( eventHead == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } int currentTime = 0; //當前時間 bool isCpuBusy = false; //CPU忙碌狀態 Event *readyQueue = new Event; //包含頭結點,就緒隊列 readyQueue->next = NULL; while ( eventHead->next != NULL ) { Event *firstEvent = FetchFirstEvent( eventHead ); currentTime = firstEvent->happenTime; if ( firstEvent->type == ARRIVALEVENT ) { if ( isCpuBusy == true ) { InsertByJobTime( readyQueue, firstEvent ); } else { isCpuBusy = true; Event *finishEvent = new Event; finishEvent->type = FINISHEVENT; finishEvent->jobBeginTime = currentTime; finishEvent->happenTime = currentTime + firstEvent->job.needTime; finishEvent->remainTime = 0; CopyJob( &(finishEvent->job), &(firstEvent->job) ); if ( firstEvent != NULL ) delete firstEvent;//刪除正在執行事件節點 firstEvent = NULL; InsertByHappenTime( eventHead, finishEvent ); } continue ; } if ( firstEvent->type == FINISHEVENT ) { ShowEvent( firstEvent ); if ( firstEvent != NULL ) delete firstEvent;//刪除已執行事件節點 firstEvent = NULL; isCpuBusy = false; Event *shortestEvent = FetchFirstEvent( readyQueue ); if ( shortestEvent != NULL ) { isCpuBusy = true; Event *finishEvent = new Event(); finishEvent->type = FINISHEVENT; finishEvent->jobBeginTime = currentTime; finishEvent->happenTime = currentTime + shortestEvent->job.needTime; finishEvent->remainTime = shortestEvent->job.needTime; CopyJob( &(finishEvent->job), &(shortestEvent->job) ); if ( shortestEvent != NULL ) delete shortestEvent;//刪除正在執行事件節點 shortestEvent = NULL; InsertByHappenTime( eventHead, finishEvent ); } } } }
2.2 最短剩余時間優先
void SRTF( Event *eventHead ) { if ( eventHead == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } int currentTime = 0; bool isCpuBusy = false; Event *readyQueue = new Event; readyQueue->next = NULL; Event *runEvent = NULL; //正在運行事件節點 while ( eventHead->next != NULL ) { Event *firstEvent = FetchFirstEvent( eventHead ); int frontTime = currentTime; //上次事件發生時間 currentTime = firstEvent->happenTime; if ( firstEvent->type == ARRIVALEVENT ) { if ( isCpuBusy == true ) { runEvent->happenTime = currentTime; runEvent->remainTime -= (currentTime - frontTime);//剩余時間 = 運行時間- 已運行時間(本次-上次時間) if ( firstEvent->remainTime < runEvent->remainTime ) { //搶斷 DeleteByJobName( eventHead, runEvent->job.name ); //刪除上次事件的結束事件,PS.若上次事件先插入,將會被刪除 InsertByRemainTime( readyQueue, runEvent ); //上次事件加入就緒隊列 runEvent = firstEvent; //上次事件已插入繼續隊列,無須釋放空間,更新本次事件 runEvent->isFirstExe = false; // Event *finishEvent = new Event; finishEvent->type = FINISHEVENT; finishEvent->jobBeginTime = runEvent->jobBeginTime;// finishEvent->happenTime = currentTime + runEvent->remainTime; finishEvent->remainTime = 0; CopyJob( &(finishEvent->job), &(runEvent->job) ); InsertByHappenTime( eventHead, finishEvent ); //插入結束事件 } else { InsertByRemainTime( readyQueue, firstEvent );//等待,加入就緒事件隊列 } } if ( isCpuBusy == false ) { isCpuBusy = true; firstEvent->isFirstExe = false; Event *finishEvent = new Event; finishEvent->type = FINISHEVENT; finishEvent->jobBeginTime = firstEvent->jobBeginTime; // finishEvent->isFirstExe = false; finishEvent->happenTime = currentTime + firstEvent->remainTime; finishEvent->remainTime = 0; CopyJob( &(finishEvent->job), &(firstEvent->job) ); runEvent = firstEvent; InsertByHappenTime( eventHead, finishEvent ); } continue ; } if ( firstEvent->type == FINISHEVENT ) { ShowEvent( firstEvent ); if ( runEvent != NULL ) //刪除已運行事件 delete runEvent; runEvent = NULL; isCpuBusy = false; Event *remainTimeEvent = FetchFirstEvent( readyQueue ); if ( remainTimeEvent != NULL ) { isCpuBusy = true; if ( remainTimeEvent->isFirstExe ) //在就緒隊列中,若作業首次執行,必然是延遲發生的 remainTimeEvent->jobBeginTime = currentTime; remainTimeEvent->isFirstExe = false; Event *finishEvent = new Event(); finishEvent->type = FINISHEVENT; finishEvent->jobBeginTime = remainTimeEvent->jobBeginTime; finishEvent->happenTime = currentTime + remainTimeEvent->remainTime; finishEvent->remainTime = 0; CopyJob( &(finishEvent->job), &(remainTimeEvent->job) ); runEvent = remainTimeEvent; InsertByHappenTime( eventHead, finishEvent ); } } } }
2.3 時間片輪轉(時間片大小為1)
void RR( Event *eventHead ) { if ( eventHead == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } int currentTime = 0; bool isCpuBusy = false; Event *readyQueue = new Event; readyQueue->next = NULL; while ( eventHead->next != NULL ) { Event *firstEvent = FetchFirstEvent( eventHead ); if ( firstEvent->happenTime > currentTime ) currentTime = firstEvent->happenTime; if ( firstEvent->type == ARRIVALEVENT ) { if ( isCpuBusy ) { InsertTail( readyQueue, firstEvent ); } else { isCpuBusy = true; Event *nextEvent = new Event; nextEvent->jobBeginTime = firstEvent->jobBeginTime; CopyJob( &(nextEvent->job), &(firstEvent->job) ); if ( firstEvent->remainTime <= TIMER ) //FinishEvent { nextEvent->type = FINISHEVENT; nextEvent->happenTime = currentTime + firstEvent->remainTime; nextEvent->remainTime = 0; InsertFinishEvent( eventHead, nextEvent ); } else //TimerEvent { nextEvent->type = TIMEREVENT; nextEvent->happenTime = currentTime + TIMER; nextEvent->remainTime = firstEvent->remainTime - TIMER; InsertByHappenTime( eventHead, nextEvent ); } if ( firstEvent != NULL ) delete firstEvent;//刪除正在執行事件節點 firstEvent = NULL; } continue ; } if ( firstEvent->type == TIMEREVENT ) { InsertTail( readyQueue, firstEvent ); } int isFinish = false; if ( firstEvent->type == FINISHEVENT ) { ShowEvent( firstEvent ); if ( firstEvent != NULL ) delete firstEvent;//刪除已執行事件節點 firstEvent = NULL; isFinish = true; } while ( firstEvent = FetchFirstEvent( readyQueue ) ) { if ( isFinish ) isCpuBusy = true, isFinish = false; Event *nextEvent = new Event; if ( firstEvent->type == ARRIVALEVENT ) nextEvent->jobBeginTime = currentTime; else if ( firstEvent->type == TIMEREVENT ) nextEvent->jobBeginTime = firstEvent->jobBeginTime; CopyJob( &(nextEvent->job), &(firstEvent->job) ); if ( firstEvent->remainTime <= TIMER ) //FinishEvent { nextEvent->type = FINISHEVENT; nextEvent->happenTime = currentTime + firstEvent->remainTime; nextEvent->remainTime = 0; InsertFinishEvent( eventHead, nextEvent ); } else //TimerEvent { nextEvent->type = TIMEREVENT; nextEvent->happenTime = currentTime + TIMER; nextEvent->remainTime = firstEvent->remainTime - TIMER; InsertByHappenTime( eventHead, nextEvent ); } currentTime = nextEvent->happenTime; if ( firstEvent != NULL ) delete firstEvent;//刪除正在執行事件節點 firstEvent = NULL; } } }
2.4 搶占式優先級調度
void Priority( Event *eventHead ) { if ( eventHead == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } int currentTime = 0; bool isCpuBusy = false; Event *readyQueue = new Event; readyQueue->next = NULL; Event *runEvent = NULL; //正在運行事件節點 while ( eventHead->next != NULL ) { Event *firstEvent = FetchFirstEvent( eventHead ); int frontTime = currentTime; //上次事件發生時間 currentTime = firstEvent->happenTime; if ( firstEvent->type == ARRIVALEVENT ) { if ( isCpuBusy == true ) { runEvent->happenTime = currentTime; runEvent->remainTime -= (currentTime - frontTime);//剩余時間 = 運行時間- 已運行時間(本次-上次時間) if ( firstEvent->job.priority < runEvent->job.priority ) { //搶斷 DeleteByJobName( eventHead, runEvent->job.name ); //刪除上次事件的結束事件,PS.若上次事件先插入,將會被刪除 InsertByPriority( readyQueue, runEvent ); //上次事件加入就緒隊列 runEvent = firstEvent; //上次事件已插入繼續隊列,無須釋放空間,更新本次事件 runEvent->isFirstExe = false; // Event *finishEvent = new Event; finishEvent->type = FINISHEVENT; finishEvent->jobBeginTime = runEvent->jobBeginTime;// finishEvent->happenTime = currentTime + runEvent->remainTime; finishEvent->remainTime = 0; CopyJob( &(finishEvent->job), &(runEvent->job) ); InsertByHappenTime( eventHead, finishEvent ); //插入結束事件 } else { InsertByRemainTime( readyQueue, firstEvent );//等待,加入就緒事件隊列 } } if ( isCpuBusy == false ) { isCpuBusy = true; firstEvent->isFirstExe = false; Event *finishEvent = new Event; finishEvent->type = FINISHEVENT; finishEvent->jobBeginTime = firstEvent->jobBeginTime; finishEvent->happenTime = currentTime + firstEvent->remainTime; finishEvent->remainTime = 0; CopyJob( &(finishEvent->job), &(firstEvent->job) ); runEvent = firstEvent; InsertByHappenTime( eventHead, finishEvent ); } continue ; } if ( firstEvent->type == FINISHEVENT ) { ShowEvent( firstEvent ); if ( runEvent != NULL ) //刪除已運行事件 delete runEvent; runEvent = NULL; isCpuBusy = false; Event *priorityEvent = FetchFirstEvent( readyQueue ); if ( priorityEvent != NULL ) { isCpuBusy = true; if ( priorityEvent->isFirstExe ) //在就緒隊列中,若作業首次執行,必然是延遲發生的 priorityEvent->jobBeginTime = currentTime; Event *finishEvent = new Event(); finishEvent->type = FINISHEVENT; finishEvent->jobBeginTime = priorityEvent->jobBeginTime; finishEvent->happenTime = currentTime + priorityEvent->remainTime; finishEvent->remainTime = 0; CopyJob( &(finishEvent->job), &(priorityEvent->job) ); runEvent = priorityEvent; InsertByHappenTime( eventHead, finishEvent ); } } } }
2.5 最高響應比優先
void HRRF( Event *eventHead ) { if ( eventHead == NULL ) { cerr << "At: " << __FILE__ << "\nLine: " << __LINE__ << endl; throw "Head Point is NULL!\n"; } int currentTime = 0; //當前時間 bool isCpuBusy = false; //CPU忙碌狀態 Event *readyQueue = new Event; //包含頭結點,就緒隊列 readyQueue->next = NULL; while ( eventHead->next != NULL ) { Event *firstEvent = FetchFirstEvent( eventHead ); currentTime = firstEvent->happenTime; if ( firstEvent->type == ARRIVALEVENT ) { if ( isCpuBusy == true ) { InsertTail( readyQueue, firstEvent ); } else { isCpuBusy = true; Event *finishEvent = new Event; finishEvent->type = FINISHEVENT; finishEvent->jobBeginTime = currentTime; finishEvent->happenTime = currentTime + firstEvent->job.needTime; finishEvent->remainTime = 0; CopyJob( &(finishEvent->job), &(firstEvent->job) ); if ( firstEvent != NULL ) delete firstEvent;//刪除正在執行事件節點 firstEvent = NULL; InsertByHappenTime( eventHead, finishEvent ); } continue ; } if ( firstEvent->type == FINISHEVENT ) { ShowEvent( firstEvent ); if ( firstEvent != NULL ) delete firstEvent;//刪除已執行事件節點 firstEvent = NULL; isCpuBusy = false; SortByHRR( readyQueue, currentTime ); Event *hrrEvent = FetchFirstEvent( readyQueue ); if ( hrrEvent != NULL ) { isCpuBusy = true; Event *finishEvent = new Event(); finishEvent->type = FINISHEVENT; finishEvent->jobBeginTime = currentTime; finishEvent->happenTime = currentTime + hrrEvent->job.needTime; finishEvent->remainTime = hrrEvent->job.needTime; CopyJob( &(finishEvent->job), &(hrrEvent->job) ); if ( hrrEvent != NULL ) delete hrrEvent;//刪除正在執行事件節點 hrrEvent = NULL; InsertByHappenTime( eventHead, finishEvent ); } } } }
測試數據
進程 |
到達時間 |
服務時間 |
優先級 |
A |
0 |
3 |
5 |
B |
2 |
6 |
2 |
C |
4 |
4 |
3 |
D |
6 |
5 |
4 |
E |
8 |
2 |
1 |
運行結果
一、最短作業時間優先
二、最短剩余時間優先
三、最高響應比優先
四、優先級調度
五、時間片輪轉
時間片=1
時間片=4
總結與體會
根據流程圖,一步一步實現功能,思路清晰,就不會出錯。PS:C#程序的可視化及其調度算法采用LINQ實現,將在下章講解。