从零开始学硬件<8>demo源码OceanOS-CM0-B6解读

从零开始学硬件<8>demo源码OceanOS-CM0-B6解读
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不受影响有临界区每次完整输出一行再切到另一个任务。有两个同优先级的任务在抢烧录后打开串口通常会看到11111和22222交替出现按照Demo的预想会打印这样Hello world111112222211111222221111122222而实际上打印的是Hello world11111111111111111111图二仔细分析下原因task1在队首→进临界区→打印→忙等时间片到了也不轮转→出临界区→调度器发现队首还是task1 →继续跑task1 →又打印11111 ...临界区里又做长时间忙等task1就不会让出同优先级队列的队首位置所以只会看到11111看不到22222。所以要对应修改task1和task2需要把耗时操作放到临界区外面这样每次打印完、退出临界区后时间片机制才能把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底层的机制就会更清晰地了解到为什么会是这个结果了。图四