关于uCOS官方互斥量函数中获取互斥量函数OSMutexPend()实现代码的疑问(stm32F4)

OSMutexPend():获取互斥量函数

{

函数思想:任务对互斥量的所有权是独占的,任意时刻互斥量只能被一个任务持有,如果互斥量处于开锁状态,那么获取该互斥量的任务将成功获得该互斥量,并拥有互斥量的使用权;如果互斥量处于闭锁状态,获取该互斥量的任务将无法获得互斥量,任务将被挂起,在任务被挂起之前,会进行优先级继承,如果当前任务优先级比持有互斥量的任务优先级高,那么将会临时提升持有互斥量任务的优先级

五个入口参数:指向互斥量的指针;超时时间;选项;被释放时的时间戳(为0表示互斥量被创建后没有被获取释放过;或者互斥量被其他任务占有,该任务超时也没能获得互斥量);返回错误类型

函数过程:① 安全检查,参数选项检查等。选项就两个:OS_OPT_PEND_BLOCKING和OS_OPT_PEND_NON_BLOCKING,就是如果互斥量被其他任务持有,该任务要不要阻塞。② 进入临界段,如果互斥量可用(开锁状态)(OwnerNestingCtr值为0),那么修改互斥量元素OwnerTCBPtr的值,把当前TCB赋给它;然后令OwnerNestingCtr加1,表示互斥量处于闭锁状态;并给返回的时间戳赋值为互斥量中时间戳元素的值;调用OS_MutexGrpAdd()将互斥量添加到所持互斥量任务的链表中,退出临界段;返回无错误类型,并return返回。③ 如果是当前任务再次获取该互斥量,那么就需要修改互斥量的OwnerNestingCtr元素,令它的值加1;返回时间戳;退出临界段;返回错误类型“OS_ERR_MUTEX_OWNER”,并return返回。④ 如果互斥量被其他任务占有,且选项类型为OS_OPT_PEND_NON_BLOCKING,那么就返回错误“OS_ERR_PEND_WOULD_BLOCK”,并return。(在任务选择“不阻塞”的条件下,可以通过这个返回类型判断互斥量是否被其他任务占用)。⑤ 如果互斥量被其他任务占有,选项类型是“OS_OPT_PEND_BLOCKING”,首先检查调度器是否被锁,(因为需要将任务添加进等待列表,如果调度器被锁,则不能进行任何任务的操作);如果没被锁,则调用OS_CRITICAL_ENTER_CPU_EXIT()锁住调度器但是打开中断;如果当前任务的优先级大于获得互斥量任务的优先级,调用OS_TaskChangePrio()修改获得互斥量任务的优先级;调用OS_Pend()将任务添加到互斥量的等待列表中;调用OS_CRITICAL_EXIT_NO_SCHED()解锁调度器并且不切换;然后调用OSSched()进行切换(因为这里任务已经进入互斥量的等待列表中,被阻塞了,所以切换)。⑥ 切换后保存了上下文,若再次执行到这里,说明任务肯定已经从阻塞态恢复了,才能继续被调度,那么就应该根据任务状态判断到底是等到了互斥量被恢复还是超时恢复等等。如果任务状态是“OS_STATUS_PEND_OK”,说明我们得到了互斥量,返回时间戳和无错误;如果任务状态是“OS_STATUS_PEND_ABORT”,返回等待终止的时间戳和“等待终止”的错误;如果是“OS_STATUS_PEND_TIMEOUT”,返回时间戳为0,表示并没有取得互斥量,并返回“等待超时”的错误;如果是“OS_STATUS_PEND_DEL”,返回互斥量被删除的错误;其他与等待无关的状态都是无效状态。

-调用OS_TaskChangePrio()

:① 因为只要任务持有互斥量,那么就拥有它的所有权,只有等待该任务调用释放互斥量的函数才会使互斥量可用。所以任务在调用释放互斥量函数之前可能会处于各种状态,比如就绪态:创建任务后,会把任务插入到就绪列表中,插入成功修改任务状态为就绪态,在任务运行过程中,如果调用涉及任务状改变的函数,那么任务状态都处于就绪态。比如延时态:在其中调用阻塞延时函数,那么就会将任务从就绪列表中移除,插入时基列表,插入成功修改状态为延时态;如果在任务还没释放互斥量时调用,任务就处于延时态。所以需要根据任务状态修改任务的优先级。② 此函数是在获取互斥量的函数OSMutexPend()中调用,在调用该函数之前,已经先调用了OS_CRITICAL_ENTER_CPU_EXIT()锁住了调度器,防止任务切换以及状态的改变(比如插入时基列表、等待列表等)。③ 修改了优先级,就应该将任务插入到对应的优先级下的就绪列表中。

两个入口参数:指向持有互斥量的任务TCB的指针;要替换的优先级

函数过程:是一个do-while循环,循环条件是TCB指针不为空。循环体内是根据任务状态修改任务的优先级及为了修改优先级而做的操作。(这里do-while循环的目的就是为了解决持有互斥量的任务访问其他互斥量保护资源的时候被阻塞在其他互斥量等待列表中)。① 如果是就绪态,说明任务还在运行中,或者还没切换到该任务。为了防止在修改任务优先级时,任务运行修改状态,先调用OS_RdyListRemove()把任务从就绪列表中移除(如果移除后该优先级下没有任务了,此函数会同时清空优先级表的对应优先级位);所以在修改完任务优先级后,调用OS_PrioInsert()在相应优先级表的位置置1,该函数使用或运算法置1,所以不用担心重复,影响其他位置;因为就绪态有两种情况:任务在运行中,那么修改了优先级后,应该让它插入就绪列表头部,好继续运行;第二种情况是可能还没切换到它(但是它持有互斥量,并没有释放),当前任务就不等于持有互斥量的任务,那么就把持有互斥量的任务插入到就绪列表尾部,因为提高了优先级,不能插到头部,让其他高优先级的任务运行等待时间变长。② 如果任务状态是延时,挂起,延时+挂起态,只改变持有互斥量任务的优先级,因为任务处于这些状态时,已经被移出就绪列表,修改了优先级,在再次切换为就绪态时,他们会自动按照优先级插入就绪列表。③ 如果是等待,超时等待,等待+挂起,超时等待+挂起,因为也从就绪列表中移除了,除了像②一样修改优先级,还要访问任务的pendon元素,看任务在等待啥。如果不是在等待互斥量(比如在等待信号量,消息队列等),应该调用OS_PendListChangePrio()修改任务在等待列表中的位置,因为等待列表是按照任务优先级串成的单向链表,修改了任务优先级,当然需要修改在链表中的位置。④ 因为一个任务可以持有多个互斥量,访问多个保护资源,如果是等待互斥量,那么除了调用OS_PendListChangePrio()修改任务在互斥量等待列表中的位置,因为任务处于其他互斥量等待列表中,又因为提高了优先级,所以需要判断是否需要提高另一个互斥量任务的优先级。如果需要,则要重走上面过程,因为这个函数就是用来修改持有互斥量任务的优先级的;如果不需要,那么就不需要重走上面的过程,退出循环。需要的情况只有一个:处于等待列表中的任务优先级大于持有互斥量的任务优先级。但是uCOS官方并没有像下面一样写判断代码。

因为OS_TaskChangePrio()函数不仅可以可以把优先级改大,也可以把优先级改小,而且并不只针对持有互斥量的任务修改优先级,其他任务也可以在运行过程中调用此函数修改优先级。只是这里获得互斥量函数OSMutexPend()调用OS_TaskChangePrio(),是为了把优先级继承,把优先级改大而已。所以uCOS官方分了两种情况:一种是把优先级改小了,prio_cur > prio_new;另一种就是不变或者改大

但是我还是觉得官方的逻辑写错了

我把我的逻辑贴出来,希望大家不吝赐教:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值