FreeRTOS学习笔记(四)

1.优先级反转

假设有三个任务,任务一的优先级为1,任务二的优先级为2,任务三的优先级为3,并且任务一与任务三需要信号量,任务二不需要,且他们的执行顺序为任务一->任务二->任务三。

任务一开始执行任务时,申请得到了信号量,执行他的任务,执行一段时间后,任务二优先级大于任务一,于是任务一被阻塞,开始执行任务二。任务二执行一段时间后,任务三开始执行,当任务三需要信号量,而此时信号量被任务一占用,任务一又被任务二阻塞,不能释放信号量,因此此时任务三会在申请信号量时被阻塞,所以调度器会执行任务二,当任务二执行完成后,任务三还没有得到信号量还是在被阻塞,执行任务一,最后才是任务三。

简单来说就是任务一被任务二阻塞了,不能释放信号量,而任务三又获得不了信号量,也被阻塞,只能执行任务二。

解决方法:使用互斥量

2.互斥量(锁)

使用互斥锁可以避免多任务的竞争冒险,提高系统的稳定性和可靠性同时它还可以解决信号量的优先级反转问题,它具备了继承功能。

流程:

互斥量初始值为1

任务A想访问临界资源,先获得并占有互斥量,然后开始访问

任务B也想访问临界资源,也要先获得互斥量:被别人占有了,于是阻塞

任务A使用完毕,释放互斥量;任务B被唤醒、得到并占有互斥量,然后开始访问临界资源

任务B使用完毕,释放互斥量

3.互斥量函数

创建:

释放和获得:

优先级继承领导临时提拔你):

假设持有互斥锁的是任务A,如果更高优先级的任务B也尝试获得这个锁

任务B说:你既然持有宝剑,又不给我,那就继承我的愿望吧

于是任务A就继承了任务B的优先级

这就叫:优先级继承

等任务A释放互斥锁时,它就恢复为原来的优先级

互斥锁内部就实现了优先级的提升、恢复

4.事件组

事件组的核心就是可以唤醒多个任务

事件组可以简单地认为就是一个整数,其中的高8位留给内核使用,只能用其他的位来表示事件:

1.每一位表示一个事件;

2.每一位事件的含义由程序员决定,比如:Bit0 表示用来串口是否就绪,Bit1表示按键是否被按下;

3.这些位,值为 1 表示事件发生了,值为 0 表示事件没发生;

4.一个或多个任务、ISR 都可以去写这些位;

5.一个或多个任务、ISR 都可以去读这些位;

6.可以等待某一位、某些位中的任意一个,也可以等待多位

两大主要区别:

唤醒谁?

队列、信号量:事件发生时,只会唤醒一个任务

事件组的事件发生时,会唤醒所有符号条件的任务,简单地说它有"广播"的作用

是否清除事件?

队列、信号量:是消耗型的资源,队列的数据被读走就没了;信号量被获取后就减少了

事件组:被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件

  1. 事件组函数

创建:

删除

设置事件

等待事件 

5.FreeRTOS为什么需要两套API函数

FreeRTOS中很多API函数都有两套:一套在任务中使用,另一套在ISR中使用。后者的函数名含有"FromISR"后缀。

为什么要引入两套API函数?

很多API函数会导致任务计入阻塞状态:运行这个函数的任务进入阻塞状态;比如写队列时,如果队列已满,可以进入阻塞状态等待一会

ISR调用API函数时,ISR不是"任务",ISR不能进入阻塞状态

所以,在任务中、在ISR中,这些函数的功能是有差别的

6.ISR函数里的xHigherPriorityTaskWoken参数

xHigherPriorityTaskWoken的含义是:是否有更高优先级的任务被唤醒了。如果为pdTRUE,则意味着后面要进行任务切换。还是以写队列为例。任务A调用 xQueueSendToBack() 写队列,有几种情况发生:

1.队列满了,任务A阻塞等待,另一个任务B运行

2.队列没满,任务A成功写入队列,但是它导致另一个任务B被唤醒,任务B的优先级更高:任务B先运行

3.队列没满,任务A成功写入队列,即刻返回

可以看到,在任务中调用API函数可能导致任务阻塞、任务切换,这叫做"context switch",上下文切换。这个函数可能很长时间才返回,在函数的内部实现了任务切换。

xQueueSendToBackFromISR() 函数也可能导致任务切换,但是不会在函数内部进行切换,而是返回一个参数:表示是否需要切换,函数原型与用法如下:

pxHigherPriorityTaskWoken参数,就是用来保存函数的结果:是否需要切换

*pxHigherPriorityTaskWoken等于pdTRUE:函数的操作导致更高优先级的任务就绪了,ISR应该进行任务切换;等于pdFALSE:没有进行任务切换的必要

ISR中有可能多次调用"FromISR"函数,如果在"FromISR"内部进行任务切换,会浪费时间。解决方法是:在"FromISR"中标记是否需要切换,在ISR返回之前再进行任务切换。

7.屏蔽/使能中断、暂停/恢复调度器

互斥功能是如何实现的?

要独占式地访问临界资源,有3种方法:

公平竞争:比如使用互斥量,谁先获得互斥量谁就访问临界资源,这部分内容前面讲过。

1、谁要跟我抢,我就灭掉谁:

2、中断要跟我抢?我屏蔽中断

3、其他任务要跟我抢?我禁止调度器,不运行任务切换

屏蔽中断:

1.在任务中屏蔽中断

2.在ISR中屏蔽中断:

屏蔽调度器:

如果有别的任务来跟你竞争临界资源,你可以把中断关掉:这当然可以禁止别的任务运行,但是这代价太大了。它会影响到中断的处理。

如果只是禁止别的任务来跟你竞争,不需要关中断,暂停调度器就可以了:在这期间,中断还是可以发生、处理。

8.中断延时处理

简单来说,就是我在ISR中断处理函数中,只记录发生了中断,好比记录一个标志位,而真正的处理是在任务中进行,这样就不会影响ISR。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值