第八章
抢占式概念
抢占式内核:即当任务正在运行,有一个更高优先级的任务出现时,如果当前内核允许抢占,则可以将当前任务挂起,执行优先级更高的任务。在我们上一章的基础上我们已经做了这个工作。说白了就是在任务创建的时候进行了任务调度,已保证更高优先级的任务能够被及时运行。
还有就是在更高优先级从非就绪态到就绪态的时候应该进行任务调度。这个场景是什么呢?比如高优先级的任务进入了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