FreeRTOS 调度锁,任务锁和中断锁
以下转载自安富莱电子: http://forum.armfly.com/forum.php
调度锁
调度锁就是 RTOS 提供的调度器开关函数,如果某个任务调用了调度锁开关函数,处于调度锁开和调
度锁关之间的代码在执行期间是不会被高优先级的任务抢占的,即任务调度被禁止。这一点要跟临界段的
作用区分开,调度锁只是禁止了任务调度,并没有关闭任何中断,中断还是正常执行的。而临界段进行了
开关中断操作。
中断锁
中断锁就是 RTOS 提供的开关中断函数,FreeRTOS 没有专门的中断锁函数,使用 前一节里面介
绍的中断服务程序临界段处理函数就可以实现同样效果。
任务锁
简单的说,为了防止当前任务的执行被其它高优先级的任务打断而提供的锁机制就是任务锁。
FreeRTOS 也没有专门的任务锁函数,但是使用 FreeRTOS 现有的功能有两种实现方法:
通过给调度器加锁实现
利用 FreeRTOS 的调度锁功能给调度器加锁的话,将关闭任务切换功能,从而高优先级任务也就无法
抢占低优先级任务的执行,同时高优先级任务也是无法向低优先级任务切换的。 另外特别注意,调度
锁只是禁止了调度器工作,并没有关闭任何中断。
通过关闭任务切换中断 PendSV 和系统时钟节拍中断 Systick
利用 FreeRTOS 的任务代码临界段处理函数就可以关闭 PendSV 中断和 Systick 中断。因为进入临界
段前,操作寄存器 basepri 关闭了所有小于等于宏定义
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 所定义的中断优先级(实现任务切换功能
的 PendSV 中断和滴答定时器中断是最低优先级中断,所以也是被关闭的),这样低优先级任务在执
行临界段代码期间是不会被高优先级任务打断的,从而就实现了任务锁的效果。
FreeRTOS 调度锁开启
使用如下函数可以实现 FreeRTOS 的调度锁开启:
vTaskSuspendAll()
函数原型:
void vTaskSuspendAll( void );
函数描述:
函数 vTaskSuspendAll 用于实现 FreeRTOS 调度锁开启。
使用这个函数要注意以下问题:
1. 调度锁函数只是禁止了任务调度,并没有关闭任何中断。
2. 调度锁开启函数 vTaskSuspendAll 和调度锁关闭函数 xTaskResumeAll 一定要成对使用。
3. 切不可在调度锁开启函数 vTaskSuspendAll 和调度锁关闭函数 xTaskResumeAll 之间调用任何会引起任务切换的 API,比如 vTaskDelayUntil、 vTaskDelay、 xQueueSend 等。
FreeRTOS 调度锁关闭
使用如下函数可以实现 FreeRTOS 的调度锁关闭:
xTaskResumeAll ()
函数原型:
BaseType_t xTaskResumeAll(void)
函数描述:
函数 xTaskResumeAll 用于实现 FreeRTOS 调度锁关闭
调度锁关闭后,如果需要任务切换,此函数返回 pdTRUE,否则返回 pdFALSE。
使用这个函数要注意以下问题:
1. 调度锁函数只是禁止了任务调度,并没有关闭任何中断。
2. 调度锁开启函数 vTaskSuspendAll 和调度锁关闭函数 xTaskResumeAll 一定要成对使用。
3. 切不可在调度锁开启函数 vTaskSuspendAll 和调度锁关闭函数 xTaskResumeAll 之间调用任何会引起任务切换的 API,比如 vTaskDelayUntil、 vTaskDelay、 xQueueSend 等。
eg:
void vTaskLed1(void *pvParameters) { /* 任务都是一个无限,不能返回 */ while(1) { vTaskSuspendAll(); /* 开启调度锁 */ printf("任务vTaskLed1正在运行\r\n"); if(!xTaskResumeAll()) /* 关闭调度锁,如果需要任务切换,此函数返回pdTRUE,否则返回pdFALSE */ { taskYIELD (); } LED3_ON; /* 阻塞延时,单位ms */ vTaskDelay( 500 ); LED3_OFF; vTaskDelay( 500 ); } }
这里需要注意红色部分,就是关闭调度锁的时候,加上了一个if判断,这个判断的目的是什么呢?是不是多余的呢?开启和关闭调度锁不是像下面这样就可的吗:
那为什么官方的demo中有这样一个判断?
先看关闭调度锁返回值的解释:
如果恢复调度造成了上下文切换,返回pdTRUE,否则返回pdFLASE。这里
要满足if,证明没有上下文切换,然后调用taskYIELD(),这个函数是强制上下文转换:
这也就证明了,如果调用xTaskResumeAll()没有进行上下文切换,我们将强制进行上下文切换,如果进行了上下文切换,这个if判断是多余的。官方解释:
另外需要注意,强制进行上下文切换,不代表本任务中xTaskResumeAll()后面的语句就不执行了,这里led灯的亮灭依旧会执行,(除非有高优先级任务打断此刻的任务了)只是调度器重新获得了调度权限,可以在多个任务间进行调度和切换。还有注意调度锁,不能锁中断。
我之前还想,要是在一个低优先级的任务中运行一段不想被高优级打断的程序时freertos怎么做,现在知道了,调度锁和临界段。
实验效果:
欢迎加入作者的小圈子
扫描下方左边二维码加入QQ交流群,扫描下方右边二维码关注个人微信公众号并获取更多隐藏干货,QQ交流群:816747642 微信公众号:Crystal软件学堂
作者:Crystal软件学堂 bilibili视频教程地址:https://space.bilibili.com/5782182 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在转载文章页面给出原文连接。 如果你觉得文章对你有所帮助,烦请点个推荐,你的支持是我更文的动力。 文中若有错误,请您务必指出,感谢给予我建议并让我提高的你。 |