(8)從1開始寫一個操作系統

第八章

搶佔式概念

搶佔式內核:即當任務正在運行,有一個更高優先級的任務出現時,如果當前內核允許搶佔,則可以將當前任務掛起,執行優先級更高的任務。在我們上一章的基礎上我們已經做了這個工作。說白了就是在任務創建的時候進行了任務調度,已保證更高優先級的任務能夠被及時運行。

還有就是在更高優先級從非就緒態到就緒態的時候應該進行任務調度。這個場景是什麼呢?比如高優先級的任務進入了sleep態,當sleep到達的時候應該在中斷中直接進行任務調度。

再比如高優先級等待的事件到達時,應該直接切換到高優先級任務運行。因爲還沒有進行任務事件的部分所以這裏暫時先不討論。

 

搶佔式內核

好了,總結一下就是高優先級任務只要從非就緒態變爲就緒態就切換任務進行運行的內核就是搶佔式內核。現在我們就來把我們唯一能做的sleep時間到時進行任務調度的工作做了吧。

我們在中斷中進行修改,爲了避免不必要的任務調度,我們設置一個變量記錄此次中斷是否需要任務調度BOOLEAN need_schedule = FALSE;

然後我們把上一張新加的中斷中任務調度代碼提取到一個if中,如下:

    if (need_schedule == TRUE) { //調度任務執行代碼
        char i = 0, j = 0;
        u8 highest_prio_id = 0;
        u8 task_sequence = 0;//當前任務的已運行隊列中一定是0
        //SP -= 2;
        os_tcb[os_task_running_ID].OSTCBStkPtr = SP;
        os_tcb[os_task_running_ID].OSTCBStatus = OS_STAT_RDY;
        //切換任務棧
        for (; i<TASK_SIZE; i++) { //找到優先級最高任務,並且是在已運行任務隊列的最後,如果已運行任務隊列中沒有則優先運行
            if (os_tcb[i].OSTCBStatus == OS_STAT_RDY) {
                if (os_tcb[i].OSTCBPrio > os_tcb[highest_prio_id].OSTCBPrio) {
                    highest_prio_id = i;
                    //查找高優先級在已運行隊列中的排位
                    task_sequence = 0xFF;//先假設這個排在最最最後面
                    for (j=0; j<TASK_SIZE; j++) {
                        if (os_task_run[j] == i) {
                            task_sequence = j;
                            break;
                        }
                        if (os_task_run[j] == 0xFF)
                         break;
                    }
                } else if (os_tcb[i].OSTCBPrio == os_tcb[highest_prio_id].OSTCBPrio) {
                    //查找新找到的高優先級在已運行隊列中的排位
                    u8 temp_task_sequence = 0xFF;//同優先級使用的臨時任務序列
                    for (j=0; j<TASK_SIZE; j++) { //查找新的同級任務在任務隊列中的排位
                        if (os_task_run[j] == i) {
                            temp_task_sequence = j;
                            break;
                        }
                        if (os_task_run[j] == 0xFF)
                         break;
                    }
                    if (temp_task_sequence > task_sequence) { //此處我們沒有考慮兩個相同優先級都沒在已運行任務隊列中的情況,這種情況下運行第一個被找到的任務
                        highest_prio_id = i;
                        task_sequence = temp_task_sequence;
                    }
                }
            }
        }
        os_task_running_ID = highest_prio_id;
        //把當前任務插入已運行任務隊列中
        {
            u8 temp_id = os_task_running_ID, temp_temp_id;
            if (task_sequence == 0xFF) { //不在任務隊列中,直接頭插
                for (j=0; j<TASK_SIZE; j++) {
                    if (os_task_run[j] == 0xFF) {
                        os_task_run[j] = temp_id;
                        break;
                    }
                    temp_temp_id = os_task_run[j];
                    os_task_run[j] = temp_id;
                    temp_id = temp_temp_id;
                }
            } else { //已在任務隊列中,在所在位置前移
                for (j = task_sequence; j>0; j--) {
                    os_task_run[j] = os_task_run[j-1];
                }
                os_task_run[0] = os_task_running_ID;
            }
        }
        if (os_tcb[os_task_running_ID].OSTCBTimeQuantaCtr == 0) //給當前運行的時間片賦值
            os_tcb[os_task_running_ID].OSTCBTimeQuantaCtr = os_tcb[os_task_running_ID].OSTCBTimeQuanta;
        os_tcb[os_task_running_ID].OSTCBStatus = OS_STAT_RUNNING;
        SP = os_tcb[os_task_running_ID].OSTCBStkPtr;
    }

如果此次中斷需要調度就把變量置起。

need_schedule = TRUE;

好了,我們改完了。

Main.C使用第6章的代碼運行結果如下:

[2019-09-10 19:09:28.314]# RECV ASCII>
STC15F2K60S2 RT-OS Test Prgramme!
app_task_1
app_task_3
app_task_2
idle_task_0 in
[2019-09-10 19:09:29.314]# RECV ASCII>
app_task_1
app_task_3
app_task_2
[2019-09-10 19:09:30.314]# RECV ASCII>
app_task_1
app_task_3
app_task_2
[2019-09-10 19:09:31.314]# RECV ASCII>
app_task_1
app_task_3
app_task_2
[2019-09-10 19:09:32.300]# RECV ASCII>
app_task_1
app_task_3
app_task_2

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章