type
status
password
date
slug
summary
category
URL
tags
icon
1. 互斥信号量的原理与创建
1.1 问题概述
1.1.1 计数信号量的不足
关于处理多个任务访问共享资源的冲突问题,之前介绍过3种方法,
- 关中断:长时间关中断不可取
- 调度锁:使用调度锁会关闭调度(即任务切换),长时间禁用也不可取
- 计数信号量:计数信号量用于互斥的几点不足之处
- 不支持嵌套调用:如果任务嵌套调用,会导致任务被挂起,进而死锁
- 不支持所有者,任意任务都能发送notify
- 无法解决优先级反转问题
注意:这里的嵌套调用是指同一个任务嵌套调用
1.1.2 优先级反转现象说明
计数信号量用于互斥的一般用法如下,
低优先级与高优先级任务共享同一份资源,但是低优先级任务抢先获得资源;此时如果有中优先级任务插入,会抢占低优先级任务控制权,间接抢占高优先级任务。
1.2 设计原理
1.2.1 互斥信号量组件
- 事件控制块:实现任务的等待与唤醒
- 锁定次数计数器:支持嵌套调用
- 拥有者:标志已经获取互斥信号量的任务
- 拥有者原始优先级:支持优先级继承,用于处理优先级反转
说明:从实现逻辑上说,要想处理优先级反转的问题,就必须记录信号量的拥有者,否则优先级比较从何而来
1.2.2 锁定计数器原理
- 嵌套获取时,计数器加一
- 逐层释放时,只有当计数器为0才唤醒等待任务(如果有的话)
1.2.3 优先级继承原理
注意1:低优先级任务运行完成后将恢复优先级
注意2:引入优先级继承只是缓解优先级反转问题,而非完全避免,因为毕竟是让低优先级的任务先运行了,只是影响被减小了
1.3 设计实现
1.3.1 定义互斥信号量类型
1.3.2 添加tMutexInit函数
2. 互斥信号量的等待与通知
2.1 设计原理
2.1.1 等待互斥信号量(信号量未被占用)
- 当前任务占有互斥信号量
- 将互斥信号量拥有者指向当前任务
- 互斥信号量拥有者原始优先级=当前任务优先级
- 将锁定次数加1
2.1.2 等待互斥信号量(信号量被自己占有)
将锁定计数加1
2.1.3 等待互斥信号量(信号量被高优先级任务占有)
无需进行优先级继承,将低优先级任务插入等待队列
2.1.4 等待互斥信号量(信号量被低优先级任务占有)
- 进行优先级继承
将当前占有互斥信号量的低优先级任务的优先级提高到与高优先级任务相同(除了需要修改任务结构体的优先级字段,还需要切换任务的就绪队列)
- 将高优先级任务插入等待队列
补充:上图中在示意优先级继承时有误,进行优先级继承时,互斥信号量中的拥有者原始优先级字段不会被修改,修改的是拥有者任务的优先级
当释放信号量时,就是根据拥有者优先级与拥有者原始优先级是否相同,来判断是否发生了优先级继承
2.1.5 释放信号量(未发生优先级继承)
- 如果发生嵌套锁定,则只是减少锁定计数
- 如果是拥有者最后一次释放信号量,则高优先级任务释放互斥信号量,并唤醒等待队列中的任务(如果有的话)
说明:互斥信号量支持拥有者属性,所以只有信号量的拥有者才能释放信号量
2.1.6 释放信号量(发生优先级继承)
- 如果发生嵌套锁定,则只是减少锁定计数
- 如果是拥有者最后一次释放信号量,则低优先级任务释放信号量,并恢复原始优先级,然后唤醒高优先级任务占有信号量(此时等待队列中一定有高优先级任务)
2.2 设计实现
2.2.1 添加tMutexWait函数
说明:从代码中可见任务处于就绪态与任务在就绪队列中必须是对应的,而之前的代码在任务在从就绪队列进入延时队列或等待队列时,并没有将就绪状态清除,这点是有问题的
补充:上面的理解有疏漏
上述代码中判断互斥信号量拥有者任务状态时使用的条件为
owner->state == TINYOS_TASK_STATE_READY
此处是状态必须等于
TINYOS_TASK_STATE_READY
,而不是最后一个比特位的状态,当任务进入延时 / 挂起 / 等待队列时,均会修改state的其他比特位,进而导致state的值不等TINYOS_TASK_STATE_READY
所以此处owner->state ==
TINYOS_TASK_STATE_READY
与任务在就绪队列中是能够对应的2.2.2 添加tMutexNoWaitGet函数
2.2.3 添加tMutexNotify函数
3. 互斥信号量的删除与状态查询
3.1 设计原理
3.1.1 互斥信号量的删除(未发生优先级继承)
① 将等待队列清空
3.1.2 互斥信号量的删除(发生优先级继承)
① 恢复互斥信号量拥有者优先级
② 将等待队列清空
3.2 设计实现
3.2.1 添加tMutexDestroy函数
3.2.2 添加tMutexGetInfo函数
为获取互斥信号量的状态,首先定义用于保存互斥信号量信息的结构
说明:在获取互斥信号量拥有者当前优先级时,首先要判断该互斥信号量是否已被占有,否则会出现空指针访问