文章目录
- 消息队列
-
- 信号量
-
- 互斥量(锁)
-
- 递归互斥量(递归锁)
-
消息队列
消息队列结构
由消息队列控制块+消息存储buffer组成,是全局变量,结构如下
消息队列控制块中的链表
List_t xTasksWaitingToSend;
List_t xTasksWaitingToReceive;
读队列步骤
step1.关中断
step2.如果buffer中有数据,goto step3
如果buffer中没数据,
如果xTicksToWait=0,开中断,返回ERR
如果xTicksToWait!=0,
把当前TCB记录到xTasksWaitingToReceive
把当前TCB从xReadyTasksLists移调到xDelayedTaskList让当前任务休眠
step3.从环形buffer拷贝数据
把xTasksWaitingToSend列表上的第一个TCB移除
把xTasksWaitingToSend列表上的第一个TCB从xDelayedTaskList移调到xReadyTasksLists唤醒需要发送的任务
step4.开中断
写队列步骤
step1.关中断
step2.如果buffer中还能写数据,goto step3
如果buffer中数据满了,
如果xTicksToWait=0,开中断,返回ERR
如果xTicksToWait!=0,
把当前TCB记录到xTasksWaitingToSend
把当前TCB从xReadyTasksLists移调到xDelayedTaskList让当前任务休眠
step3.拷贝数据到环形buffer
把xTasksWaitingToReceive列表上的第一个TCB移除
把xTasksWaitingToReceive列表上的第一个TCB从xDelayedTaskList移调到xReadyTasksLists唤醒需要发送的任务
step4.开中断
注意,上述是有任务主控发送接收导致对端唤醒,还有一种方式是延时时间到了由tick中断来唤醒
作用
常用于任务间数据传递
信号量
信号量结构
信号量借用的消息队列数据结构,用uxMessagesWaiting来代指资源个数,二值信号量就是这个值只能是0和1,且没有后面的buffer,如下,所以发送接收和队列基本相同
获取信号量
step1.关中断
step2.如果uxMessagesWaiting>0,goto step3
如果uxMessagesWaiting=0,
如果xTicksToWait=0,开中断,返回ERR
如果xTicksToWait!=0,
把当前TCB记录到xTasksWaitingToReceive
把当前TCB从xReadyTasksLists移调到xDelayedTaskList让当前任务休眠
step3.uxMessagesWaiting--
把xTasksWaitingToSend列表上的第一个TCB移除
把xTasksWaitingToSend列表上的第一个TCB从xDelayedTaskList移调到xReadyTasksLists唤醒需要发送的任务
step4.开中断
释放信号量
step1.关中断
step2.如果uxMessagesWaiting已经是最大值,开中断,返回ERR
step3.uxMessagesWaiting++
把xTasksWaitingToReceive列表上的第一个TCB移除
把xTasksWaitingToReceive列表上的第一个TCB从xDelayedTaskList移调到xReadyTasksLists唤醒需要发送的任务
step4.开中断
注,二值信号量存在优先级翻转问题,就是高优先级任务因为低优先级任务占用了资源且低优先级任务被高于他优先级任务抢占导致不能运行,这样高优先级就一直阻塞住了,为了解决此问题(减小影响)设计了互斥量
互斥量(锁)
互斥量结构
互斥量就是二值信号量+优先级继承,xMutexHolder保存拿到此资源的TCB,TCB中还有一个uxBasePriority用于保存此任务创建时的优先级
获取互斥量
step1.关中断
step2.如果uxMessagesWaiting>0,xMutexHolder记录TCB,goto step3
如果uxMessagesWaiting=0,
如果xTicksToWait=0,开中断,返回ERR
如果xTicksToWait!=0,
用当前任务优先级改写xMutexHolder任务优先级
把当前TCB记录到xTasksWaitingToReceive
把当前TCB从xReadyTasksLists移调到xDelayedTaskList让当前任务休眠
step3.uxMessagesWaiting--
把xTasksWaitingToSend列表上的第一个TCB移除
把xTasksWaitingToSend列表上的第一个TCB从xDelayedTaskList移调到xReadyTasksLists唤醒需要发送的任务
step4.开中断
释放互斥量
step1.关中断
step2.如果uxMessagesWaiting已经是最大值,开中断,返回ERR
step3.uxMessagesWaiting++
用uxBasePriority来恢复自身优先级
把xTasksWaitingToReceive列表上的第一个TCB移除
把xTasksWaitingToReceive列表上的第一个TCB从xDelayedTaskList移调到xReadyTasksLists唤醒需要发送的任务
step4.开中断
注,FreeRTOS没有实现谁take谁give的限制,所以一个task take,另一个task give在代码上是能跑通的,要注意这点
还有死锁问题,一个任务先take后再次take,此任务就被阻塞了,无法唤醒,自我死锁,此时需要用递归互斥量
递归互斥量(递归锁)
递归互斥量和临界区嵌套设计方式一样,uxRecursiveCallCount来记录递归次数,且递归互斥量实现了谁take谁give的限制。
获取递归互斥量
如果xMutexHolder == 当前TCB,uxRecursiveCallCount++,返回
如果xMutexHolder != 当前TCB,调用互斥量take,返回
释放递归互斥量
如果xMutexHolder == 当前TCB,uxRecursiveCallCount--,
如果uxRecursiveCallCount==0,调用互斥量give
如果xMutexHolder != 当前TCB,返回
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)