从零开始学硬件<7>demo源码OceanOS-CM0-B5解读
2026/7/7 15:29:17 网站建设 项目流程

B5课程:时间片调度

B4优先级问题,处理的是:谁更急,谁先跑。B5换一个问题:优先级一样的时候,怎么办?这就是时间片调度。代码改动不大,烧进去以后,串口输出会和B4完全不同。

示例在干什么

(图一)

main_task还是老样子:初始化串口和LED,亮500ms、灭500ms。优先级仍是1

这次创建了两个子任务,task1task2,优先级都是2

os_task_create(al_task1,NULL,"task1",

&g_task1_tcb,g_task1_stack,AL_TASK1_STACK_SIZE,2);

os_task_create(al_task2,NULL,"task2",

&g_task2_tcb,g_task2_stack,AL_TASK2_STACK_SIZE,2);

两个任务的循环也几乎一样,只是打印内容不同:

voidal_task1(void*arg)

{

while(1)

{

printf("11111\r\n");

}

}

voidal_task2(void*arg)

{

while(1)

{

printf("22222\r\n");

}

}

这次有两个同优先级的任务在抢,烧录后打开串口,通常会看到1111122222交替出现,如图二所示:

(图二)

时间片从哪来

OceanOS里,每个TCB有个tick_slice字段。注释写得很直白:0xFF表示这个任务独占CPU0表示时间片用完了。

默认时间片长度在os_config.h里:

#defineOS_TASK_TICK_SLICE_DEFAULT4

4tick,也就是4msSysTick配的是1ms一次)。

调度器选下一个任务时,会看同优先级队列里还有没有别的任务:

g_os_tcb_upcoming->tick_slice=(g_os_tcb_upcoming->next_tcb)?

OS_TASK_TICK_SLICE_DEFAULT:OS_TASK_TICK_SLICE_CLOSE;

有「邻居」——同优先级下还有别的任务——就分配4tick,开启时间片轮转。队列里只有自己——就设成0xFF,关时间片,独占CPU,和B4里高优先级独占的情况一样。

时间片怎么转

每个SysTickos_tick_beat(),如果当前任务在运行、且时间片开着,计数就减1

减到0时,内核会做一件事:把这个任务从就绪表当前位置摘下来,挂到同优先级队列末尾,状态改回就绪,等下次调度再轮上来。

if(g_os_tcb_current->tick_slice==0)

{

if(g_os_tcb_current->next_tcb)

{

os_tcb_table_remove(&g_os_ready_tcb_table,g_os_tcb_current);

os_tcb_table_insert(&g_os_ready_tcb_table,g_os_tcb_current);

g_os_tcb_current->task_status=OS_TASK_STATUS_READY;

}

}

同优先级队列是双向链表,先来先服务,时间片用完就排到队尾。task14mstask2上,task24ms,再换回task1——串口上1111122222就这样交错出来。

如果同优先级只有一个任务,时间片关闭,可以一直占着CPU,直到更高优先级任务就绪,或者自己阻塞。B4task1就是这种情况:优先级0队列里只有它一个,又从不阻塞,所以低优先级的main_task几乎没机会跑。

B4B5放在一起看

B4教的是「等级」:数字越小越优先,高等级可以压着低等级跑。那个实验有点极端,但极端才看得清楚。

B5教的是「公平」:等级相同,不能永远让先创建的那个霸占CPU。时间片像发牌,每人摸几张,摸完轮到下家。

实际项目里两种机制一起用:紧急任务给高优先级;同级别的采集、通信、日志打印,靠时间片轮流跑,避免某一个把CPU吃死。

B5的小结

B5demo阐述的问题一样重要时,怎么分。

log打印的1111122222的比例不一定严格1:1printf本身耗时、上下文切换开销、调度时机,都会让某一边偶尔多打几行。这是正常的,不是

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询