• 沒有找到結果。

Operating Systems Project 2

N/A
N/A
Protected

Academic year: 2022

Share "Operating Systems Project 2"

Copied!
5
0
0

加載中.... (立即查看全文)

全文

(1)

1

Operating Systems Project 2

資工三 B94902032 陳縕儂、資工三 B94902007 張詩平

目的:將原先的 FCFS 的排程方式改成 Mutilevel Round-Robin 的排程方式

These files we have modified:

(1) code/machine/stats.h

加了兩個新的 pubic 變數,分別是 mrrTicks 和 timeslice,mrrTicks 紀錄 current thread 執行的 tick 總數,timeslice 紀錄 time quantum,為了判定 current thread 執行的 tick 數是否已經到了 time slice,若是的話,則要讓下一個 thread執行。原有的 totalTicks 為總共執行的 tick 數,之後會用到它。

(2) code/threads/thread.h

在 Thread 的 class 中加了一個 function MrrSched,以及兩個 variable,分別是 priority 和 load,紀錄單一一個 thread 的 priority 和 remaining time。

(3) code/threads/main.cc

在 main 中判斷參數 argv[i]有沒有-S 的存在,並設定一個 flag 去紀錄。若有-S,則將 flag 設為 true,之後將-S 後方的參數(一個 file 的 name)傳進 kernel->currentThread->MrrSched()中,並且讓 MrrScahed()去讀 input file。

class Thread { public:

void MrrSched(char *ParameterFile);

int priority; // save a thread's priority int load; // save a thread's remaining time };

class Statistics { public:

int totalTicks; // Total time running Nachos int mrrTicks; // the time unit

int timeslice; // the time slice

Statistics(); // initialize everything to zero

void Print(); // print collected statistics };

int

main(int argc, char **argv) {

int road;

bool ParameterFileFlag = false;

:

for (i = 1; i < argc; i++) { :

else if (strcmp(argv[i], "-S") == 0) { ParameterFileFlag = TRUE;

road = i;

} }

:

if (ParameterFileFlag) {

kernel->currentThread->MrrSched(argv[road + 1]);

} : }

(2)

2

(4) code/threads/thread.cc

新增一個新的 function,void Thread::MrrSched (char *ParameterFile),首先是先將傳進來的 file 裡面的 data 讀進 來,放入 kernel->stats->timeslice 和 num 裡面,然後接著就 new 出每個 thread,並且對每個 thread 分別存它們 自己的 priority 和 load,然後傳進 t->Fork((VoidFunctionPtr)SimpleThread, (void *)i)中去 schedule 之。

對原有的 SimpleThread 這個 function 做修改,當 current thread 的 remaining time 還沒被減到 0 時,就要一直 去 run 此 thread,其中每 run 一個 tick 的時間,就會將 current thread 的 info output 出來,同時也計算總共執 行的 tick,每 run 完一次,就將 kernel->stats->totalTicks 加 1。

※由於我們這次的 scheduling algorithm 是 Round-Robin 的 scheduling,所以我們必須要 invoke 一個

interrupt(kernel->interrupt->OneMrrTick())去隨時判斷此時的 current thread 是否已經執行了 time slice 的時間。

若已經執行了 time slice 的 tick 數,就應該要放棄 CPU,並且換下一個 thread 去 run。

(5) code/machine/interrupt.h

在 interrupt 的 class 新增一個新的 public function 為 OneMrrTick()。為了去紀錄現在總共執行的 tick 數及 current thread的 remaining time,並且判斷當執行的 tick 到達 time quantum 則要放棄 CPU 換給下一個 thread 執行。

void

Thread::MrrSched (char *ParameterFile) {

FILE *fin = fopen(ParameterFile, "r"); //Parse the parameter file Thread *t;

int num;

int i;

fscanf(fin, "%d", &kernel->stats->timeslice);

fscanf(fin, "%d", &num);

for(i = 0; i < num; i ++) {

t = new Thread("forked thread"); //create thread

fscanf(fin, "%d%d", &t->priority, &t->load); //set parameter: priority, remaining execution time t->Fork((VoidFunctionPtr)SimpleThread, (void *)i);

}

kernel->currentThread->Yield(); //* Give up CPU

}

static void

SimpleThread(int which) {

while(kernel->currentThread->load > 0){

printf("MrrThread %c at %2d. ", which + 65, kernel->stats->totalTicks);

kernel->stats->totalTicks ++;

printf("(%c's priority = %d, %c's load = %d)\n",

which + 65, kernel->currentThread->priority, which + 65, kernel->currentThread->load);

kernel->interrupt->OneMrrTick();

} }

class Interrupt { : public:

void OneMrrTick();

: };

(3)

3

(6) code/machine/interrupt.cc

新增一個OneMrrTick的function,每當執行時,mrrTicks會加1去紀錄此時執行的tick數,並且將current thread的 load減1。當有任何一個thread做完的時候(load = 0),就將mrrTicks歸零,為了避免下一個thread在跑的時候,執 行的tick數會多加上了前一個thread所用的tick數(因為前一個thread可能還沒到time slice的tick就已經結束),所 以在此thread結束時,就把mrrTicks歸零,重新計算。

※如果kernel->stats->mrrTicks可以被kernel->stats->timeslice整除的話,代表現在執行的tick數已經到了time slice 的限制(假如timeslice = 2,mrrTicks = 2、4、6…),由於我們使用的是Round-Robin的scheduling algorithm,所以 當執行的tick數已到了time quantum時,current thread就應該要放棄CPU,並且去找下一個thread執行(利用 kernel->currentThread->Yield()讓呼叫它的thread suspend並且找尋下一個thread去執行)。

(7) code/threads/scheduler.h

在scheduler的class中,增加一個public的List array,大小為11,代表總共有11個readylist,每個list分別放置相同 priority的thread(priority是1~10,main會被放置在0中),當我們去schedule的時候,先將一個list裡面的thread都 做完,才會做下一個list的。(先將priority相同的用RR的方式run完,才做下一個level的list中的thread)。

(8) code/threads/scheduler.cc

在一開始,先new出11個List,分別當做不同priority的readylist。

void

Interrupt::OneMrrTick() {

kernel->stats->mrrTicks ++; // time of execution kernel->currentThread->load --; // remaining time

if(kernel->currentThread->load == 0){

kernel->stats->mrrTicks = 0;

}

if(kernel->stats->mrrTicks % kernel->stats->timeslice == 0){

kernel->currentThread->Yield();

} }

class Scheduler { :

public:

List<Thread *> *mrrList[11];

: };

Scheduler::Scheduler() {

int i;

for(i = 0; i <= 10; i ++){

mrrList[i] = new List<Thread *>;

}

toBeDestroyed = NULL;

}

(4)

4

將傳進來的thread加在它的priority對應的list中(mrrList[i]),若前面已有thread存在,則加在後面(Append)。

從priority = 1的開始排程,若此list還沒有empty的話,代表它要繼續做下一個應該要執行的thread,故利用 RemoveFront()把最前面的thread回傳回去。然後一直到此list空了以後,才跑下一個level的list裡面的thread。當 所有的priority都跑完以後,再去執行main,因為main的priority會等於0,所以它會被放到mrrList[0]裡面的readylist 中,所以我們去看mrrList[0]是否為空的,若非,則繼續去執行之。

(9) code/threads/thread.cc

當有thread呼叫Yield()後,加一個判斷,如果它的load不等於0的話(代表它還沒有做完),而且它所在的list卻是 empty,則將下一個要執行的thread設為它自己,讓它繼續擁有CPU。

void

Scheduler::ReadyToRun (Thread *thread) {

ASSERT(kernel->interrupt->getLevel() == IntOff);

DEBUG(dbgThread, "Putting thread on ready list: " << thread->getName());

thread->setStatus(READY);

mrrList[thread->priority]->Append(thread);

}

Thread *

Scheduler::FindNextToRun () {

int i;

ASSERT(kernel->interrupt->getLevel() == IntOff);

for(i = 1; i <= 10; i ++){

if(mrrList[i]->IsEmpty() == 0){

return mrrList[i]->RemoveFront();

} }

if(mrrList[0]->IsEmpty() == 0){

return mrrList[0]->RemoveFront();

}

return NULL;

}

void

Thread::Yield () {

Thread *nextThread;

IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);

ASSERT(this == kernel->currentThread);

DEBUG(dbgThread, "Yielding thread: " << name);

if(kernel->currentThread->load != 0 && kernel->scheduler->mrrList[kernel->currentThread->priority]->IsEmpty() == 1){

nextThread = kernel->currentThread;

return;

}

nextThread = kernel->scheduler->FindNextToRun();

if (nextThread != NULL) {

kernel->scheduler->ReadyToRun(this);

kernel->scheduler->Run(nextThread, FALSE);

}

(void) kernel->interrupt->SetLevel(oldLevel);

}

(5)

5

(10) code/threads/kernel.cc & code/machine/interrupt.cc

根據Project2的power point第23頁,mark這兩個file裡的兩行code。分別是alarm = new Alarm(randomSlice)及 OneTick()。

中途所遭遇到的困難

一開始就想好要將不同priority的thread放到不同的readylist中,然後照順序分別對每個list去做。

問題1:

較後執行的thread,會將前一個已經結束的thread的執行tick數也加在mrrTicks中,所以可能會造成thread B才跑 一單位時間,就換下一個thread的情況。解決這個問題的方法上面已經解釋過了,就是在interrupt中判斷此時 thread是否已經做完(load是否為0),若是的話,代表它已經要結束了,所以就將mrrTicks歸零,避免影響到下一 個執行的thread。

問題2:

一開始不知道main會被放到priority是0的readylist中,所以先前在scheduler的時候就一直有錯誤。所以後來就將 priority是0的readylist在其它thread已經跑完之後,最後再執行。

問題3:

在 Scheduler::FindNextToRun ()裡面,每次都判斷 current thread 的 list 是否為空的,若為空的則做下一個 level 的 thread。但是如果此 level 還沒有 empty,但是它的 readylist 中只剩它自己,所以當我們利用

mrrList[i]->RemoveFront()去找 list 中最前面的 thread 時,同時會先將 current thread 丟到 list 的最後面,而 mrrList[i]->IsEmpty()因為沒有馬上找到最前面的 thread,所以它會以為此 list 已經空了(但實際上不是),結果此 thread就被跳過了。解決此問題的方法就是在 Yield()中加的一些判斷。因為當上述情況發生,而可能產生錯誤 之時,代表此 thread 還沒結束(load 不等於 0),而且 list 又被判定為 empty,此時原本會 Yield()掉,然後把 CPU 換給下一個 thread,此 thread 就不會結束了。所以當這些判斷情況成立的時候,我們將 nextThread 設為 currentThread,如此一來,此 thread 就可以繼續執行而不會被跳過了^0^。

※寫完此project以後,覺得了解不少其中內部運作的情形,還滿有成就感的。

參考文獻

相關文件

1993年6月英國劍橋牛頓研究所舉辦了 一個討論會, 主題是 Iwasawa 理論, 自守形 式 與 p-進表現。 在這次討論會上, A.Wiles 給了一系列演講, 講題是: 橢圓曲線模形式與 Galois 表現。 在演講最後

有一位老師提議重考, 因 為學生沒讀好書, 再考一次, 可以讓學生有 機會好好地再讀 一次, 以補強前面所學的不 足。 但最後以加分來 「粉飾太平」, 不過是美 化 「帳 面」 而已, 於事何補..

[r]

Morse 則將此問題考慮到高維度上, 如何去 找封閉測地 線。 有關測地線的問題尚有 ,在二 維的封閉曲面上至少有 3 條不自交的封閉測 地 線, 這是很有名的問題, 直到最近才有詳細 的 證明。

對平面上的任意凸多邊形作適當的圖形分割, 可以求出此凸多邊形面積的一般公式。 分割 一個給定的凸多邊形時, 不同的分割方法, 所求得的面積公式也不盡相同; 其最大差異在於所求

此時的訊號乃是上下振盪,但向下的資料點對鼾聲判斷並沒有幫助,因此採用尋 找區域最大值的方式來去掉不必要的訊號,也就是每 10 個資料點中比較出一個最大 值來代表這

報戶口:1 位學生當查戶口的人,有幾位 學生代表戶長站在最前面,其他 學生可以排在戶長的後面,當查 戶口的人去詢問戶長時問: 「你

這裡最重要的便是 要知道, 以後我們找一個方陣或一個 linear operator 的 minimal polynomial 的方法便是先 找到它的 characteristic polynomial, 然後再利用上一個 Theorem