外观
相互调用实现任务伪切换
约 816 字大约 3 分钟
2025-12-09
为了更好地使用RTOS,我们需要深入理解RTOS工作原理,最好的方法是动手写一个RTOS。
如果你希望写一个类似RT-Thread/FreeRTOS的系统,欢迎关注这门课程:【RTOS内核开发】从0手写嵌入式操作系统
在理解了函数调用后是如何返回这一原理之后,接来下就可以正式去深入RTOS的任务切换实现机制。本小节将使用两个任务函数,来演示如何实现任务切换。
RTOS任务切换示例
前面提到过,引入RTOS后,开发人员可以创建多个任务分别用于执行不同的功能,从而将原本较复杂的功能分解为多个较简单的小任务去完成,这样实现起来更为简单。
在创建的多个任务中,每个任务往往是包含for(;;)循环,并在循环中监测某些事件是否发生并处理。当任务需要睡眠、等待事件时,可以调用RTOS的某些任务,让CPU去执行其它任务。
void task2_entry (void * arg) {
task2_flag = 0;
for (;;) {
task2_flag ^= 1;
os_task_sleep(100); // 延时
}
}
void task3_entry (void * arg) {
task3_flag = 0;
for (;;) {
task3_flag ^= 1;
os_sched_yield(); // 主动放弃CPU
}
}那么,如何实现从某个任务函数切换到其它任务函数去执行,并且在某个时候再切换回来执行呢?
由于具体的实现原理较为复杂,我们将通过后续一系列文章来讲解。本文章先看一种非常简单的实现方法。
最简单的处理方法
参考前面小节的内容可知:如果想在一个函数中去执行另一个函数的代码,可以直接调用这个函数。因此,在main.c中添加如下代码。具体来说,有两个任务函数task_0_entry和task_1_entry,这两个任务函数通过函数调用的方式切换执行。
void task_0_entry (void) {
int count = -1;
for (;;) {
count++;
task_1_entry();
}
}
void task_1_entry (void) {
int count = 0;
for (;;) {
count++;
task_0_entry();
}
}
int main (void) {
task_0_entry();
for (;;) {}
return 0;
}以上程序在运行之后,首先进入main()中执行,然后进入task_0_entry()执行。之后,在task_0_entry()中进入task1_entry(),再由task_1_entry()切换回task_0_entry(),如此反复。
这样在一定程度上能够实现两个任务函数交替运行,但是也存在两个致命的问题:
- 每次切换时,都必须从任务函数的入口处运行。例如,在task_0_entry()中调用task_1_entry(),只会每次都进入到task1_entry()开头的地方开始运行。
- 由于函数相互调用,并且永远不会返回,因此最终会发生栈溢出,导致程序运行出现崩溃。
这告诉了我们什么
从上面的现像可知,仅仅采用函数调用的方式并不能正常实现任务函数执行的切换。因此,我们需要采用其它方法来克服前面提到的两个问题。如果解决这个问题;那么就可以实现一个类似成熟RTOS中的任务切换功能。
具体如何解决这个问题,将在下一节课时中处理。
