更詳細(xì)的講解和代碼調(diào)試演示過程,請(qǐng)參看視頻
Linux kernel Hacker, 從零構(gòu)建自己的內(nèi)核
我們有了進(jìn)程調(diào)度,目前來看,所有進(jìn)程一律平等。我們的調(diào)度算法是遍歷每一個(gè)進(jìn)程,然后給每一個(gè)進(jìn)程一定的運(yùn)行時(shí)間,然后再切換下一個(gè)進(jìn)程。但實(shí)際運(yùn)用上,進(jìn)程間不會(huì)是平等的,有些進(jìn)程承擔(dān)著比較重要的工作,因此,它有理由獲得更多的運(yùn)行時(shí)間,例如內(nèi)核進(jìn)程,一些進(jìn)程不是很重要,同理,它就不應(yīng)該占用過度的CPU資源。本節(jié),我們要引入進(jìn)程優(yōu)先級(jí)的功能,讓優(yōu)先級(jí)高的進(jìn)程獲得更多的運(yùn)行機(jī)會(huì)。
首先我們需要改動(dòng)的是對(duì)TASK結(jié)構(gòu)體的定義(multi_task.h):
struct TASK {
int sel, flags;
int priority;
struct TSS32 tss;
};
我們?cè)黾恿艘粋€(gè)變量叫priority, 這個(gè)變量代表著進(jìn)程的優(yōu)先級(jí),同時(shí)也是進(jìn)程運(yùn)行的時(shí)間片,這個(gè)值越大,進(jìn)程獲得的CPU運(yùn)行時(shí)間就越多。TASK對(duì)象的相關(guān)處理函數(shù)也需要做相應(yīng)改動(dòng),在multi_task.c中:
struct TASK *task_init(struct MEMMAN *memman) {
....
task = task_alloc();
task->flags = 2; //active
task->priority = 100;
taskctl->running = 1;
taskctl->now = 0;
taskctl->tasks[0] = task;
load_tr(task->sel);
task_timer = timer_alloc();
timer_settime(task_timer, task->priority);
return task;
....
}
void task_run(struct TASK *task, int priority) {
if (priority > 0) {
task->priority = priority;
}
task->flags = 2;
taskctl->tasks[taskctl->running] = task;
taskctl->running++;
return;
}
void task_switch(void) {
struct TASK *task;
if (taskctl->running >= 2) {
taskctl->now++;
if (taskctl->now == taskctl->running) {
taskctl->now = 0;
}
task = taskctl->tasks[taskctl->now];
timer_settime(task_timer, task->priority);
farjmp(0, taskctl->tasks[taskctl->now]->sel);
}
return;
}
每個(gè)任務(wù)分配時(shí),它的優(yōu)先級(jí)會(huì)默認(rèn)設(shè)置成100,也就是該任務(wù)能獲得1秒的運(yùn)行時(shí)間。task_run多增加了一個(gè)參數(shù),也就是任務(wù)優(yōu)先級(jí),當(dāng)一個(gè)任務(wù)準(zhǔn)備加入調(diào)度隊(duì)列時(shí),需要指定它的優(yōu)先級(jí),在task_switch中,任務(wù)切換時(shí),我們通過timer_settime來設(shè)置任務(wù)的運(yùn)行時(shí)間,大家可以看到,時(shí)鐘的長(zhǎng)度設(shè)置為task->priority, 也就是說,任務(wù)的優(yōu)先級(jí)同時(shí)也是任務(wù)的CPU運(yùn)行時(shí)間。
任務(wù)激活的相關(guān)代碼也需要做改動(dòng),任務(wù)可以對(duì)應(yīng)一個(gè)數(shù)據(jù)隊(duì)列,當(dāng)隊(duì)列有數(shù)據(jù)抵達(dá)時(shí),隊(duì)列會(huì)把存儲(chǔ)在其中的任務(wù)加入調(diào)度隊(duì)列,這個(gè)功能的實(shí)現(xiàn)是在golobal_define.c中,因此,我們也需要做相應(yīng)改動(dòng):
int fifo8_put(struct FIFO8 *fifo, unsigned char data) {
....
if (fifo->task != 0) {
if (fifo->task->flags != 2) {
task_run(fifo->task, 0);
}
}
....
}
當(dāng)任務(wù)重新被激活時(shí),我們傳入的優(yōu)先級(jí)數(shù)值是0,根據(jù)task_run的實(shí)現(xiàn),當(dāng)優(yōu)先級(jí)數(shù)值為0時(shí),任務(wù)保持原有優(yōu)先級(jí)不變。最后需要改動(dòng)的是主入口函數(shù),在write_vga_desktop.c中:
void CMain(void) {
....
for (i = 0; i < 2; i++) {
....
task_run(task_b[i], (i+1)*5);
...
}
....
}
我們?yōu)榈谝粋€(gè)任務(wù)分配的優(yōu)先級(jí)是5,第二個(gè)任務(wù)的優(yōu)先級(jí)是10,也就是第二個(gè)任務(wù)得到的CPU時(shí)間是第一個(gè)任務(wù)的2倍。將上面代碼編譯運(yùn)行時(shí)可以得到下面結(jié)果:
我們可以看到,第二個(gè)窗口計(jì)數(shù)數(shù)值大概是第一個(gè)窗口的2倍,這是因?yàn)榈诙€(gè)窗口對(duì)應(yīng)的進(jìn)程獲得的CPU運(yùn)行時(shí)間是第一個(gè)窗口兩倍的緣故。
本節(jié)代碼比較簡(jiǎn)單,這是為了下一次實(shí)現(xiàn)更復(fù)雜的進(jìn)程調(diào)度功能:優(yōu)先級(jí)隊(duì)列做準(zhǔn)備的,通過視頻可以獲得更加詳細(xì)的代碼講解和演示效果。
更多技術(shù)信息,包括操作系統(tǒng),編譯器,面試算法,機(jī)器學(xué)習(xí),人工智能,請(qǐng)關(guān)照我的公眾號(hào):