ucosIII_使用互斥信号量解决优先级反转问题。用于实现对临界资源的独占式处理,降低优先级反转带来的影响。
信号量的二值信号量可以作为一个标志flag,当两个任务访问同一个资源时,进行加锁解锁。如果当多个任务要访问同一个资源,使用二值信号量很容易带来优先级反转的问题,而这种问题,是操作系统极其不期望出现的问题(破坏任务的预期顺序,可能会导致严重的后果),所有引入互斥信号量解决优先级反转问题。
1.什么是优先级反转
假设有3个任务,优先级从高到底分别是任务H(high)M(middle)L(low)。
任务H和任务L使用互斥信号量访问同一临界资源,任务M不使用临界资源。
图1 任务HML发生优先级反转
图1(1):L任务正在使用某临界资源(信号加锁),H任务被唤醒,执行H任务。但L任务并未执行完毕,此时临界资源还未释放(互斥信号量还处于加锁状态,即使优先级更高的任务也无法访问这个临界资源) 图1(2):这个时刻H任务也要对该临界资源进行访问,但L任务还未释放资源,由于保护机制,H任务进入阻塞态,L任务得以继续运行,此时已经发生了优先级翻转现 图1(3):某个时刻M任务被唤醒,由于M任务的优先级高于工任务,M任务抢占了CPU的使用权,M任务开始运行,此时L任务尚未执行完,临界资源还没被释放 图1(4):M任务运行结束,归还CPU使用权,L任务继续运行。 图1(5):L任务运行结東,释放临界资源(信号解锁),H任务得以对资源进行访问,H任务开始运行。
说的通俗点就是,任务H和任务L都会访问一个临界资源区,通过互斥信号量加锁解锁没问题。任务H和任务L会互相等待对方加锁或解锁,这个也没问题。但是任务M优先级比任务L优先级高,本来任务H等着任务L解锁互斥信号量呢,结果CPU不去执行任务L,CPU被任务M抢了,任务H本来是想等任务L的信号呢,现在还要等任务M执行完,才能让任务L解锁信号量。那任务H可是最高优先级啊,任务H不能忍了。所有任务H把任务L的优先级提到和自己一般高(通过互斥信号量自动完成),这样任务M无法打断任务L了。等任务H获得了这个信号量,在把任务L的优先级调回原来的级别。
那到底什么是优先级反转呢?
我的理解:两个任务使用互斥信号量访问同一资源,由于其他任务抢占了其中某个任务的CPU使用时间,导致另一个任务不能及时接收或发送这个互斥信号量。使得一个任务等待互斥信号量的时间变长。
使用互斥信号量解决上面这个问题:
图2 使用互斥信号量解决优先级反转
图2(1):L任务正在使用某临界资源,L任务正在使用某临界资源,H任务被唤醒执行H任务。但L任务并未执行完毕,此时临界资源还未释放 图2(2):某一时刻任务也要对该资源进行访问,由于保护机制,H任务进入塞态。此时发生优先级继承,系统将L任务的优先级暂时提升到与H任务优先级相同,L任务继续执行 图2(3):在某一时刻M任务被唤醒,由于此时M任务的优先级暂时低于L任务,所以M任务仅在就绪态,而无法获得CPU使用权。 图2(4):L任务运行完毕,H任务获得对资源的访问权,H任务从阻塞态变成运行态,此时L任务的优先级会变回原来的优先级。 图2(5):当H任务运行完毕,M任务得到CPU使用权,开始执行 图2(6):系统正常运行,按照设定好的优先级运行
2.互斥信号量的API
文件os_mutex.c
2.1创建信号量
void OSMutexCreate (OS_MUTEX *p_mutex, CPU_CHAR *p_name, OS_ERR *p_err)
第一个参数是互斥信号量,我们要先定义一个
OS_MUTEX MyMutex; //定义一个互斥信号量
第二个参数是互斥信号量的名字
第三个参数是记录 返回值的,用于保存错误信息
OS_ERR MutextErrRet//定义一个互斥信号量错误返回值
2.2发送互斥信号量
void OSMutexPost (OS_MUTEX *p_mutex, OS_OPT opt, OS_ERR *p_err)
第一个参数是互斥信号量
第二个参数默认模式和不使用调度
第三个参数是记录返回值,用于保存错误信息
2.3请求信号量
void OSMutexPend (OS_MUTEX *p_mutex, OS_TICK timeout, OS_OPT opt, CPU_TS *p_ts, OS_ERR *p_err)
第一个参数是互斥信号量的变量
第二个参数是请求互斥信号量的超时时间
第三个参数设置阻塞还是不阻塞
第四个参数是时间戳
第五个参数是错误返回值
2.4删除互斥信号量
OS_OBJ_QTY OSMutexDel (OS_MUTEX *p_mutex,
OS_OPT opt,
OS_ERR *p_err)
3.互斥信号量的注意事项
(1) 但是使用互斥量的时候一定需要注意:在获得互斥量后,请尽快释放互斥量,同时需要注意的是在任务持有互斥量的这段时间,不得更改任务的优先级。UCOS的优先级继承机制不能解决优先级反转,只能将这种情况的影响降低到最小,硬实时系统在一开始设计时就要避免优先级反转发生
(2)互斥量的使用比较单一,因为它是信号量的一种,并且它是以锁的形式存在。在初始化的时候,互斥量处于开锁的状态,而被任务持有的时候则立刻转为闭锁的状态。互斥量更适合于:
可能会引起优先级翻转的情况。
任务可能会多次获取互斥量的情况下,这样可以避免同一任务多次递归持有而造成死锁的问题。
(3)互斥量不能在中断服务函数中使用,因为其特有的优先级继承机制只在任务起作用,而在中断的上下文环境中毫无意义。
图片引用于野火资料22.1 互斥量的基本概念,关于API的具体使用查看UCOSIII/Source/OS_Mutex.c。在野火文档基础上添加了自己的理解,有不准确的地方希望大佬指正。