java開發系統核心 實現程序優先順序佇列

2021-07-26 06:26:25 字數 3839 閱讀 2975

前幾節,我們實現了程序的排程,並給每個程序賦予相應優先順序,優先順序高的程序,能夠得到更多的cpu時間。但在演示時,我們發現乙個問題,就是,當程序傳送切換時,滑鼠鍵盤的響應會被卡死,這是因為響應滑鼠鍵盤事件的程序被調到後台,無法獲得cpu執行時間,從而不能處理滑鼠或鍵盤事件。

這種情況對使用者來說,是不可接受的。對使用者輸入給予及時回應,直接關係到使用者體驗。所以負責相應使用者輸入的程序,其重要性要比那些只需要在後台執行,不用和使用者直接互動的程序高很多。由此,我們需要實現的是,只要使用者有輸入,那麼負責處理使用者輸入的程序就不能被打斷,為了實現這個目的,我們需要實現程序的優先順序佇列。

如上圖,我們把所有程序根據level分成三個佇列,程序越重要,它對應的level值越低,這樣,當進行程序排程時,程序排程器先檢視level等於0的佇列是否還有程序,有的話,只執行該佇列的程序,如果該佇列不止乙個程序,那麼每個程序根據他們的優先順序獲得相應的cpu時間。

如果levelw為0的佇列沒有可排程的程序,那麼level為1的佇列中的程序才有獲得排程的機會,以此類推。

由此,我們看看相關資料結構的定義,首先是multi_task.h:

struct task ;

#define max_tasks 5

#define max_tasks_lv 3

#define max_tasklevels 3

#define task_gdt0 7

#define size_of_task 120

struct tasklevel ;

#define size_of_tasklevel (8+ 4*max_tasks_lv)

struct taskctl ;

task結構體增加了乙個level變數,用於表明程序的重要性。tasklevel對應於上圖的程序佇列,相同重要性的程序,都儲存在對應tasklevel的tasks陣列中。

taskctl 也就是程序管理器,其儲存的不再是程序,而是程序的優先順序佇列,它要找到重要性最高的程序佇列,從中取出程序進行排程。

multi_task.c 需要進行相應改動:

struct taskctl *get_taskctl() 

void init_task_level(int level)

}

init_task_level 對程序優先順序佇列進行初始化,running表示改對了中有幾個程序,now表示佇列中,哪個程序正在被排程到前台進行執行。

struct task  *task_init(struct memman *memman)
上面**用於初始化執行cmain函式的程序,它把cmain程序的level設定為0,也就是該程序的重要性最高,只要它不被掛起,那麼它始終擁有被排程的權利。task_add會根據程序的重要性,將其加入對應的優先順序佇列,一旦有新程序加入,task_switchsub 則修改相應排程資訊,以便程序排程器做出適當調動。

void task_run(struct task *task,int level, int priority) 

if (priority > 0)

if (task->flags == 2 && task->level != level)

if (task->flags != 2)

taskctl->lv_change = 1;

return;

}

task_run 的作用是修改程序重要性或優先順序,或者把新的程序根據其重要性新增到相應佇列。如果程序的重要性有改動,那麼通過task_remove把程序從原有的優先順序佇列中去除,然後再通過task_add將程序新增到對應的佇列。

void task_switch(void) 

if (taskctl->lv_change != 0)

new_task = tl->tasks[tl->now];

timer_settime(task_timer, new_task->priority);

if (new_task != now_task && new_task != 0)

return;

}

task_switch 被時鐘中斷呼叫,它的邏輯傳送不小變化。taskctl->now_lv表示當前正則被排程的優先順序佇列,例如,如果now_lv的值是0,那麼表示當前level等於0的佇列中的程序才可以獲得被排程的機會。task_switch 通過taskctl->now_lv得知哪個程序佇列應該被排程,然後從該佇列中,取出task物件進行執行。如果有新的程序加入,或有程序的重要性被改變了,那麼taskctl->lv_change的值就不等於0。假設當前獲得排程機會的是level值為1的佇列中的程序,但是有level等於0的程序物件新增到了level等於0的佇列中,那麼此時,排程演算法就會停止從level為1的佇列中去排程程序,而是切換到level為0的佇列,從中獲取要排程的程序。

int  task_sleep(struct task *task) }}

return0;}

struct task *task_now(void)

void task_add(struct task *task)

task_sleep 用於刪除程序,如果需要殺掉某個程序,那麼可以使用該函式剝奪指定程序物件獲得排程的權利。task_remove負責把程序從它所在的佇列中刪除,如果當前被掛起的程序是正在執行的程序,那麼task_sleep會選擇下乙個合適的程序進行排程執行。

task_now 用於返回當前正在被呼叫的程序物件,task_add把給定程序加入對應的優先順序佇列。

void task_remove(struct task *task) 

}tl->running--;

if (i < tl->now)

if (tl->now >= tl->running)

task->flags = 1;

for (; i < tl->running; i++)

return;

}void task_switchsub(void)

}taskctl->now_lv = i;

taskctl->lv_change = 0;

}

task_remove主要負責把程序物件從佇列中刪除,並修改相應的佇列資料。一旦有程序刪除或新增,那麼程序排程需要作出對應的調整,task_switchsub的作用是根據程序的新增或刪除,修改程序排程器的相應資訊,進而改變程序排程器的排程行為。

最後是主入口函式cmain也做相應改動:

void cmain(void) 

....

}

主要到,我們把執行兩個窗體的程序其重要性設定成1,也就是只要執行主入口函式的程序不掛起,那麼執行兩個窗體的程序就不能得到執行。

本節**改動雖多,但邏輯簡單,理解起來應該不難,經過上面的改動後,系統執行的情況如下:

從上圖看出,如果cmain程序執行時,上面兩個窗體原來的計數字串沒有顯示,這是因為兩個窗體的程序得不到排程的機會。由於cmain程序負責相應滑鼠鍵盤,因此,此時我們移動滑鼠就不再出現卡頓的情形。

當cmain程序被掛起後,兩個窗體的程序獲得執行機會,因而窗體中的計算字串就出現了:

java開發系統核心 自動化程序切換

我們已經通過時鐘中斷完成了兩個程序間的相互切換。但當前實現有很大的缺陷,例如我們只能在兩個指定的程序間切換,如果要想增添新的程序,那麼,沒增加乙個程序,按照當前模式,我們只能再增加相應 這顯然是不可接受的。因此,這節,我們希望完成程序的切換機制,使得有新程序時,我們無需改動 程序的管理機制會自動把新...

Java開發作業系統核心 實現程序的優先順序切換

為了保護系統核心不受惡意程式的破壞,我們原來的做法是專門為應用程式分配單獨使用的記憶體,使得應用程式對資料的讀寫都限制在核心給他分配的記憶體段內。程式對記憶體段的讀寫,完全是由ds暫存器指向的全域性描述符決定的,如果惡意程式通過修改ds暫存器的值,使得它在執行時,讓ds暫存器指向核心資料段的全域性描...

java開發系統核心 依靠多工實現多視窗

為了讓多工的特性展示的更直觀,本節,我們基於多工的基礎上,為系統實現多個視窗特效,每個視窗都執行於乙個任務或程序。由於視窗基於各自不同的程序,因此視窗自身的變化更新不會影響到其他視窗。void cmain void int i 0 for i 0 i 2 i sheet slide shtctl,s...