从零开始学硬件<8>demo源码OceanOS-CM0-B6解读
2026/7/7 16:25:21 网站建设 项目流程

B6课程:使用临界区

B6的核心问题是:多任务并发访问共享资源时,如何保证一段代码「原子执行、不被打断」?答案就是临界区(Critical Section)。

前面B5已经实现了时间片调度:同优先级的任务会轮流运行。但如果两个任务同时用串口打印,输出可能被打断、混在一起。临界区就是用来解决这类问题的——让一段代码执行完之前,不会被其他任务切走。

(图一)

两个任务同优先级,都用临界区包住打印和延时:

void al_task1(void *arg)

{

while (1)

{

OS_TASK_CRITICAL_ENTER();

printf("11111\n");

al_busy_delay(5000*1000);

OS_TASK_CRITICAL_EXIT();

}

}

void al_task2(void *arg)

{

os_tick_delay(100);

while (1)

{

OS_TASK_CRITICAL_ENTER();

printf("22222\n");

al_busy_delay(5000*1000);

OS_TASK_CRITICAL_EXIT();

}

}

代码预想达到的效果:

task2先延时100ms,让task1先跑

al_busy_delay是空循环忙等,配合临界区演示「切不走」

主任务(优先级更高)单独闪LED,不受影响

有临界区:每次完整输出一行,再切到另一个任务。

有两个同优先级的任务在抢,烧录后打开串口,通常会看到1111122222交替出现,

按照Demo的预想,会打印这样:

Hello world
11111

22222

11111

22222

11111

22222

而实际上打印的是:

Hello world
11111

11111

11111

11111

(图二)

仔细分析下原因:task1在队首进临界区打印忙等(时间片到了也不轮转)

出临界区调度器发现队首还是task1 →继续跑task1 →又打印11111 ...

临界区里又做长时间忙等,task1就不会让出同优先级队列的队首位置,所以只会看到11111,看不到22222

所以要对应修改:task1task2,需要把耗时操作放到临界区外面,这样每次打印完、退出临界区后,时间片机制才能把task1挪到队尾,task2才有机会运行。

void al_task1(void *arg)

{

while (1)

{

OS_TASK_CRITICAL_ENTER();

printf("11111\n");

al_busy_delay(5000*1000);

OS_TASK_CRITICAL_EXIT();

}

}

void al_task2(void *arg)

{

os_tick_delay(100);

while (1)

{

OS_TASK_CRITICAL_ENTER();

printf("22222\n");

al_busy_delay(5000*1000);

OS_TASK_CRITICAL_EXIT();

}

}

(图三)

修改完后,按预期的打印。后期有兴趣可以研究下os_tick.c底层的机制,就会更清晰地了解到为什么会是这个结果了。

(图四)

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

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

立即咨询