嵌入式操作系统FreeRTOS(资源管理)

一、资源管理

        (1)基本临界区

        基本临界区是指宏taskENTER_CRITICAL()与taskEXIT_CRITICAL()之间的代码区间

        #define taskENTER_CRITICAL()        portENTER_CRITICAL()

        #define taskEXIT_CRITICAL()          portEXIT_CRITICAL()

        临界区是提供互斥功能的一种非常原始的实现方法。临界区的工作仅仅是简单地把中断全部关掉,或是关掉优先级在configMAX_SYSCAL_INTERRUPT_PRIORITY及以下的中断——依赖于具体使用的 FreeRTOS 移植。

0:任务切换时关闭所有中断   1:任务切换时关闭中断优先级为1、2、3的中断  2:任务切换时关闭中断优先级为2、3的中断  3:任务切换时关闭中断优先级为3的中断

        #define configMAX_SYSCALL_INTERRUPT_PRIORITY    0

临界区嵌套是安全的,因为内核有维护一个嵌套深度计数。临界区只会在嵌套深度为0时才会真正退出——即在为每个之前调用的taskENTER_CRITICAL()都配套调用了taskEXIT_CRITICAL()之后。

         (2)挂起(锁定)调度器

        也可以通过挂起调度器来创建临界区。挂起调度器有些时候也被称为锁定调度器。基本临界区保护一段代码区间不被其它任务或中断打断。由挂起调度器实现的临界区只可以保护一段代码区间不被其它任务打断,因为这种方式下,中断是使能的。如果一个临界区太长而不适合简单地关中断来实现,可以考虑采用挂起调度器的方式。但是唤醒(resuming, or un-suspending)调度器却是一个相对较长的操作。所以评估哪种是最佳方式需要结合实际情况。

        vTaskSuspendAll() API 函数

        void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION;

        通过调用vTaskSuspendAll()来挂起调度器。挂起调度器可以停止上下文切换而不用关中断。如果某个中断在调度器挂起过程中要求进行上下文切换,则个这请求也会被挂起,直到调度器被唤醒后才会得到执行。在调度器处于挂起状态时,不能调用FreeRTOS API函数。

        xTaskResumeAll() API 函数

        BaseType_t xTaskResumeAll( void ) PRIVILEGED_FUNCTION;

        嵌套调用vTaskSuspendAll()和 xTaskResumeAll()是安全的,因为内核有维护一个嵌套深度计数。调度器只会在嵌套深度计数为0时才会被唤醒——即在为每个之前调用的vTaskSuspendAll()都配套调用了xTaskResumAll()之后。

        (3)互斥量(及二值信号量)

        互斥量是一种特殊的二值信号量,用于控制在两个或多个任务间访问共享资源。单词MUTEX(互斥量)源于“MUTual EXclusion”

        在用于互斥的场合,互斥量从概念上可看作是与共享资源关联的令牌。一个任务想要合法地访问资源,其必须先成功地得到(Take)该资源对应的令牌(成为令牌持有者)。 当令牌持有者完成资源使用,其必须马上归还(Give)令牌。只有归还了令牌,其它任务才可能成功持有,也才可能安全地访问该共享资源。一个任务除非持有了令牌,否则不允许访问共享资源。

        用于互斥的信号量必须归还。

        用于同步的信号量通常是完成同步之后便丢弃,不再归还。

        xSemaphoreCreateMutex() API函数

#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )

        互斥量是一种信号量。FreeRTOS 中所有种类的信号量句柄都保存在类型为xSemaphore

Handle的变量中。

        互斥量在使用前必须先创建。创建一个互斥量类型的信号量需要使用xSemaphoreCreate

Mutex() API函数。

返回值:

        如果返回NULL表示互斥量创建失败。原因是内存堆空间不足导致FreeRTOS无法为互斥量分配结构数据空间。第五章提供更多关于内存管理方面的信息。

        返回非NULL值表示互斥量创建成功。返回值应当保存起来作为该互斥量的句柄。

        (4)优先级反转

采用互斥量提供互斥功能的潜在缺陷之一。在这种可能的执行流 程描述中,高优先级的任务2竟然必须等待低优先级的任务1放弃对互斥量的持有权。高优先级任务被低优先级任务阻塞推迟的行为被称为”优先级反转”。这是一种不合理的 行为方式,如果把这种行为再进一步放大,当高优先级任务正等待信号量的时候,一个介于两个任务优先之间的中等优先级任务开始执行——这就会导致一个高优先级任务在等待一个低优先级任务,而低优先级任务却无法执行!

        (5)优先级继承

        FreeRTOS 中互斥量与二值信号量十分相似——唯一的区别就是互斥量自动提供了一个基本的”优先级继承”机制。优先级继承是最小化优先级反转负面影响的一种方案 ——其并不能修正优先级反转带来的问题,仅仅是减小优先级反转的影响。优先级继承使得系统行为的数学分析更为复杂,所以如果可以避免的话,并不建议系统实现对优先级继承有所依赖。优先级继承暂时地将互斥量持有者的优先级提升至所有等待此互斥量的任务所具 有的最高优先级。持有互斥量的低优先级任务”继承”了等待互斥量的任务的优先级。

        (6)死锁

        死锁是利用互斥量提供互斥功能的另一个潜在缺陷。Deadlock 有时候会被更戏剧 性地称为”deadly embrace(抱死)”。

        当两个任务都在等待被对方持有的资源时,两个任务都无法再继续执行,这种情况就被称为死锁。考虑如下情形,任务A与任务B都需要获得互斥量X与互斥量Y以完 成各自的工作:

  1. 任务A执行,并成功获得了互斥量X。
  2. 任务A被任务B抢占。
  3. 任务B成功获得了互斥量Y,之后又试图获取互斥量X——但互斥量X已经被任务A持有,所以对任务B无效。任务B选择进入阻塞态以等待互斥 量X被释放。
  4. 任务A得以继续执行。其试图获取互斥量Y——但互斥量Y已经被任务B 持有而对

        任务A无效。任务A也选择进入阻塞态以等待互斥量Y被释放。

        这种情形的最终结局是,任务A在等待一个被任务B持有的互斥量,而任务B也在等待一个被任务 A 持有的互斥量。死锁于是发生,因为两个任务都不可能再执行下去了。和优先级反转一样,避免死锁的最好方法就是在设计阶段就考虑到这种潜在风险,这样设计出来的系统就不应该会出现死锁的情况。于实践经验而言,对于一个小型嵌入式系统,死锁并不是一个大问题,因为系统设计者对整个应用程序都非常清楚,所以能够找出发生死锁的代码区域,并消除死锁问题。

        (7)守护任务

        守护任务提供了一种干净利落的方法来实现互斥功能,而不用担心会发生优先级反转和死锁。守护任务是对某个资源具有唯一所有权的任务。只有守护任务才可以直接访问其守护的资源——其它任务要访问该资源只能间接地通过守护任务提供的服务。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值