任务执行函数return后程序会去往何方

1 摘要
在有RTOS的嵌入式系统中,应用程序大多采用多任务的方式,创建多个task,每个task做一项独立的工作,任务之间采用消息队列等方式进行通信。通常情况下,每个任务都采用循环等待消息的方式阻塞,当有外部事件到来时(一般都是中断触发),其发送消息到其中的一个task,交由该task进行处理,如果需要的话,该task又会将消息传递给下一个task之后,它自己再次进入阻塞状态。
写成伪代码的形式就是如下所示:
Task_Function()
{
    while(1){
    wait_for_a_message();
    handle_this_message();
}
}
可是,任务也有鞠躬尽瘁的时候,如果用户不需要该任务了怎么办?好办,各个RTOS都提供了删除任务task_free的函数,将该task的资源进行回收,并退出调度。熟悉windows编程的同学都知道,windows AfxBeginThread创建的线程可以多种方式将其停止,但是最好的一种,是在其任务处理函数里返回,让windows内核去回收该线程的资源。那么RTOS里也是这样吗?任务执行函数return之后,程序会去往何方?本文将会结合几种RTOS的源码进行分析。
2 Nucleus
Nucleus系统里,创建task的函数是NU_Create_Task,该API需要传入一个函数指针task_entry,就是任务执行函数的起始地址。在函数实现内部,会动态申请一个任务控制块(TCB)的数据结构,并将传入的task_entry保存到TCB里,后续在任务调度时使用。
Nulceus的调度函数是TCT_Control_To_System,它也是采用类似于UCOSII的2级查表法来寻找优先级最高的就绪态task,并对其进行调度,所谓调度,就是执行其任务函数。核心调度程序找到应该执行的task,其实就是找到了它的TCB,将它的指针赋值给全局的TCD_Execute_Task(它永远指向当前正在运行的任务TCB),完成任务上下文的切换之后,会跳转到一个所有任务公用的函数TCC_Task_Shell里,由该函数来间接调用任务函数。它的实现如下面的图所示。

一般来说,任务执行函数都是一个死循环,将会在第一句tc_entry这个函数里循环执行,不再退出。
如果该函数退出,将会走到下面的TCC_Suspend_Task,看名字就知道,这个函数会将任务挂起,并将任务的状态设置为运行结束(NU_FINISHED),此后将退出调度。这种方式在用户角度看来,好像这个任务就不存在了,似乎是很“优雅”地完成了它的使命,但实际上,任务控制块等内存资源并没有被释放。补充说明一下,Nucleus里提供了一个API叫NU_Reset_Task,它可以将NU_FINISHED状态的任务复位,转为就绪态,并重新加入调度序列,从任务函数的开头再次执行。
3 FreeRTOS
我们还是要从task创建的地方入手,FreeRTOS里,先看它的任务创建函数 xTaskCreate,它的入参vTaskCode就是任务函数,xTaskCreate里首先调用了prvAllocateTCBAndStack来分配任务TCB和栈空间,然后,初始化占空间的函数pxPortInitialiseStack就来了,以Cortex-M3为例,它的实现如下:

假设任务执行函数名叫task_func,设想一下,如果是从其他函数中调用task_func(),那么C语言编译器就会先将调用task_func()函数的返回地址保存到堆栈中,再将参数保存到堆栈中。但是FreeRTOS里,task_func自己就是入口,没有一个类似以Nucleus里的Tcc_Task_Shell函数调用它,所以FreeRTOS内核需要需要模拟编译器的这种动作,建立一个任务的堆栈结构,好像这段任务代码被调用过一样。pxPortInitialiseStack()就是做了这个模拟。
首先压如堆栈的是Cortex-M3中的程序状态寄存器xPSR,紧接着,就是PC指针,因为在初始化状态,PC指针当然就是任务函数的起始地址。PC的下一个是LR寄存器,也就是我们想找的返回地址。FreeRTOS里把它设成了0!也就是说,任务函数一返回,就会跳到0地址去执行,必然会导致死机(会处理器PC跳转到异常向量表,往往等在那里是就是一个死循环)。
那么问题来了,我如果就想让某个task函数运行到一定程度就return,并且自动退出调度,有办法吗?
有的,在你的任务函数结尾处return之前,加上下面这行代码吧
vTaskDelete(NULL);
UCOSII里使用了和FreeRtos类似的办法,有兴趣的朋友可以 自行查看源码和验证之。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值