嵌入式系统uC/OS-III的结构和代码剖析(二)

首先,什么是任务

我想了一个比喻,小明在一家小吃店工作,该小吃店提供炸鸡翅和奶茶。那么小明在服务过程中需要做两件事,一件是炸鸡翅,另一件是做奶茶,那么这两件事就比喻为两个任务,而炸鸡翅和做奶茶是在一个店里的两个不同位置做,那么这个两个位置就比喻为每个任务的“工作场所”——即任务堆栈。在uC/OS-III中,每个任务都像我们以前写的函数类似,其结构为:

// 任务1
void task1(void *p_arg)
{
...
}
// 任务2
void task2(void *p_arg)
{
...
}

如task1和task2是两个任务执行入口,其各自的堆栈也需要创建,这些在后面会详细解析。

然后,在处理器中任务切换的本质是什么

那么,什么是任务切换呢?上面比喻中,假如小明在炸鸡翅,在炸的过程中没那么快就炸好,于是小明放下手中的工具,走到做奶茶的地方并拿起做奶茶的工具开始做奶茶,那么这个过程就是任务切换了。即上例中在执行task1代码过程中跳转到task2代码中去执行。那么这个过程在处理器层面上看的本质是什么?
首先,也许你需要一些处理器基础,如cpu是如何执行代码的。我在这里简要说一下,处理器会根据PC值而去执行PC指向的代码,而执行代码过程中产生的过程量会在处理器的工作寄存器(通用寄存器等)中产生,在执行task1的任务过程中,这些工作寄存器会存放这执行task1时产生的这些过程量,那么此时如果任务切换要进行task2代码的执行,那么这些过程量(包括返回地址)肯定要被保存起来,然后PC再指向task2的代码位置,使得CPU去执行task2,并且在寄存器中产生task2的过程量,当又回来接着执行task1的时候,那么这些task2的过程量也肯定需要被保存起来,然后CPU去执行之前执行过的task1时,原先task1临时保存起来的过程量又被恢复,使得此时工作寄存器里面装载的是task1的过程量,这样才实现了两个任务独立运行而不出错。以小明炸鸡翅和做奶茶为例,假如小明的双手就是工作寄存器,那么在小明炸鸡翅过程中,他手中可能拿着一些酱料或者半成品鸡翅,那么假如此时他要去做奶茶,他就需要把这些手中的东西存放好,洗好手再去做奶茶,然后做奶茶过程中要回来继续炸鸡翅也一样把保存好手中做奶茶的那些材料,洗干净手再回来炸鸡翅。否则,如果小明手里拿着还没炸好的鸡翅跑去做奶茶,他很可能把鸡翅丢进奶茶杯里然后做出奶茶给客户吃,我在想,这样的奶茶估计只有程序猿才能吃得下吧!所以,任务切换(也叫上下文切换),要搞明白的就是如何保存和恢复执行任务过程中的那些过程量。

Cortex-M3的任务切换机制

说明:本系列uC/OS-III的结构和代码剖析是基于M3的,所以会涉及到一些M3的知识点,但是不进行详讲,相关知识点可以查阅一些资料。接下来说一下Cortex-M3的任务切换机制。
Cortex-M3的任务切换机制是通过触发一个PendSV异常,然后在这个异常中进行上下文切换,这样的机制在M3中的特点就是不会造成需要及时响应的高优先级中断被抢占,因为PendSV异常的优先级低,当在执行高优先级中断时需要的上下文切换会因为PendSV异常的低优先级而被先挂起实现延时切换,那么高优先级中断或异常就会及时得到响应,这也是实时系统的硬性要求。那么M3中断和异常清单可以看"M3权威指南"详细介绍:在这里插入图片描述在这里插入图片描述
可以看到PendSV异常优先级可以设定,在uC/OS-III中把它设定为最低优先级的异常。详细怎么设定以及怎么在异常中进行切换的实现之类的,后续会在代码中进行解析。
PendSV异常就像是一个载体,因为这个载体具有可以被挂起而不抢占其他高优先级中断的特点,那么我们的上下文切换在这个载体上实现,就非常合理了,可以很好地实现实时操作系统的实时响应,又实现上下文切换带来的多任务执行。
这一节先到这里,下一节就具体地从代码并结合M3相关知识点进行剖析!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值