ucos互斥信号量解决优先级反转问题
在可剥夺性的内核中,当任务以独占方式使用共享资源的时候,会出现低优先级任务高于高优先级任务运行的情况,这种情况叫做优先级反转,对于实时操作系统而言,这是一场灾难,下面我们来说说优先级反转的典型环境.
我们假设有三个任务a,b,c,a优先级高于b,b优先级高于c,a和c都需要访问一个共享资源s,保护该资源的信号量为互斥信号量,
假设当前任务c申请了信号量访问s,还没有释放,此时任务a开始运行,那么a就会剥夺c的运行而运行a,当a去访问资源s的时候,因为得不到信号量,所以必须释放以等待信号量,任务c得以重新运行,到这里流程都是正常的,信号量的设计也是为了满足这个功能,但是,当任务c在运行并准备释放信号量的时候,任务b开始运行,那么任务b就要剥夺任务c的运行,这个时候系统就只有b在运行,而a能打断b的运行但是需要信号量,可是c优先级比较低得不到运行,这样,a就只能等到b运行完主动释放使用权才能得到运行了.
到这里问题就发生了,优先级比较高的a在优先级比较低的b运行的时候无法抢断,可剥夺性内核却剥夺不了,系统故障,在这种故障极大地降低了系统的实时性
以上说的情况就是操作系统的优先级反转
而ucos为了解决这种问题,在互斥信号量中引入了优先级提升的方法,他的基本思想是:让当前获得互斥信号量的任务的优先级短暂提升到系统可以接受的最大优先级,尽量让该任务快速的完成并释放信号量,释放之后在恢复为任务原来的优先级别.
原理说完了,接下来我们来看看代码,之前已经说过互斥信号量的部分实现,那部分不再赘述,集中看优先级提升的部分,优先级的提升我们可以猜测应该在一个任务在获取了信号量之后完成的,那也就是说,应该在ospendxxx函数里面
查看OSMutexPend函数,发现其中果然有玄机,如下
pip = (INT8U)(pevent->OSEventCnt >> 8u);
if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;
pevent->OSEventPtr = (void *)OSTCBCur;
if (OSTCBCur->OSTCBPrio <= pip) {
OS_EXIT_CRITICAL();
*perr = OS_ERR_PIP_LOWER;
} else {
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
}
Pip变量是保存在OSEventCnt中的,当我们创建信号量的时候,就会给定这个值,这个值也就是系统能够将等待该互斥信号量的任务提升的最高优先级
当一个任务请求信号量的时候,如果有信号量空余,将当前请求信号量的任务的优先级放到OSEventCnt的低八位中,
if (OSTCBCur->OSTCBPrio <= pip)
如果当前请求信号量的任务的优先级高于最高提升优先级(数值上低于),那直接运行,没必要提升优先级,否则的话,就要进行下面的操作
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
ptcb = (OS_TCB *)(pevent->OSEventPtr);
if (ptcb->OSTCBPrio > pip) {
if (mprio > OSTCBCur->OSTCBPrio) {
y = ptcb->OSTCBY;
if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0u) {
OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
if (OSRdyTbl[y] == 0u) {
OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
}
rdy = OS_TRUE;
这一段的意思就是当优先级低于最高可提升优先级的时候,将系统就绪表中的原来的ready标志清除掉,接下来
ptcb->OSTCBPrio = pip;
ptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3u);
ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07u);
ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);
ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);
if (rdy == OS_TRUE) {
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
} else {
pevent2 = ptcb->OSTCBEventPtr;
if (pevent2 != (OS_EVENT *)0) {
pevent2->OSEventGrp |= ptcb->OSTCBBitY;
pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
}
OSTCBPrioTbl[pip] = ptcb;
将当前任务的优先级切换成提升优先级,并把快速访问就绪表的元素的数据改变,同时修改系统就绪表,将提升优先级的任务的新优先级在任务就绪表中设置成就绪,最后,在tcb表中对应pip的位置,设置为提升了优先级的任务的tcb.
这样,任务的优先级就被提升了,系统下一次被调用的时候,就会按照被提升了优先级的任务的新优先级来进行调度.
既然优先级能被提升,那么也应该要能被降下来,而这个降下来应该需要依靠ospostxxx在释放信号量的时候执行,我们查看OSMutexPost代码,可以看到
if (OSTCBCur->OSTCBPrio == pip) { OSMutex_RdyAtPrio(OSTCBCur, prio);
}
也就是说,当释放信号量的任务的优先级为等于互斥信号量最高可提升优先级的时候,需要通过OSMutex_RdyAtPrio函数来将任务的优先级恢复,prio的来源是从事件中获取的优先级,大家还记得记得提升之前的优先级保存到了哪里?就是保存在这里, OSEventCnt的低八位
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;
恢复优先级的函数为OSMutex_RdyAtPrio,核心代码为
y = ptcb->OSTCBY;
OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
if (OSRdyTbl[y] == 0u) {
OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
}
ptcb->OSTCBPrio = prio;
OSPrioCur = prio;
#if OS_LOWEST_PRIO <= 63u
ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 3u) & 0x07u);
ptcb->OSTCBX = (INT8U)(prio & 0x07u);
#else
ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0x0Fu);
ptcb->OSTCBX = (INT8U) (prio & 0x0Fu);
#endif
ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);
ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
OSTCBPrioTbl[prio] = ptcb;
流程与之前提权其实是类似的,只是一个换成高优先级一个换成低优先级
先将高优先级的任务的任务就绪表中对应的位清除,然后重新设置任务的原始优先级以及当前任务优先级(释放信号量和申请信号量的是同一个任务),然后设置快速访问就绪任务表的数据元素,重新设置任务就绪表,最后将tcb数组中对应原始优先级的数据指针设置到指向任务tcb,这样就实现了任务的恢复.
到这里,就说明白了互斥信号量的优先级提升流程,要注意一点,如果使用互斥信号量的优先级提升,那么那个可提升最高优先级必须不能对应有相应的用户任务,因为ucos不允许两个任务有相同的优先级!切记切记
ucos互斥信号量解决优先级反转问题的更多相关文章
- ucos之互斥信号量及优先级反转
在ucos常使用共享资源来作为任务之间的通信方式,其中有:消息队列,信号量,邮箱,事件.信号量中又分二值信号,多值信号,互斥信号.这次主要讲二值信号与互斥信号之间区别和使用. 首先了解一下ucos的任 ...
- UCOSIII互斥信号量
互斥信号量可以解决优先级反转问题 优化后现象 优化方法:L和H等待同一个信号量的时候,将L任务优先级提至H相同优先级 实验举例 void start_task(void *p_arg) { OS_CR ...
- 【原创】xenomai内核解析--同步互斥机制(一)--优先级倒置
版权声明:本文为本文为博主原创文章,转载请注明出处.如有错误,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ 目录 一.xenomai 资源管理简要 二.优先级倒 ...
- 【freertos】011-信号量、互斥量及优先级继承机制源码分析
目录 前言 11.1 任务同步 11.2 信号量概念 11.3 二值信号量 11.3.1 二值信号量概念 11.3.2 优先级翻转 11.3.3 二值信号量运作机制 11.4 计数信号量 11.4.1 ...
- 【C# 线程】优先级反转与优先级继承
什么是优先级反转(翻转)优先级反转,是指在使用信号量时,可能会出现的这样一种不合理的现象,即: 高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度.但其他中等优先级的任务却能抢到CP ...
- 优先级反转实验,使用信号量实现【RT-Thread学习笔记 5】
RTOS中很经典的问题.就是在使用共享资源的时候,优先级低的进程在优先级高的进程之前执行的问题.这里模拟这种情况. 下面的实验模拟了优先级反转的情况: 先定义三个线程: //优先级反转实验 rt_se ...
- 【iCore4 双核心板_uC/OS-II】例程七:互斥信号量
一.实验说明: 在介绍互斥信号量前,我们先简单地描述一下什么是优先级反转.使用实时内核心,优先级反转问题是实时系统中出现得最多的问题.假设任务H优先级高于任务M,任务M优先级高于任务L.任务H和任务M ...
- UCOSIII优先级反转
反转现象 任务优先级:H>M>L 绿色部分:任务占用共享资源 理想状态:7释放信号量后,最高优先级H任务抢占CPU 反转原因:H和L等待同一个信号量,H的任务优先级被降至和L相同优先级,此 ...
- RTX——第15章 互斥信号量
以下内容转载自安富莱电子: http://forum.armfly.com/forum.php 本章节开始讲解 RTX 的另一个重要的资源共享机制---互斥信号量(Mutex,即 Mutual Exc ...
随机推荐
- 从零开始学习OpenGL ES之一 – 基本概念
我曾写过一些文章介绍iPhone OpenGL ES编程,但大部分针对的是已经至少懂得一些3D编程知识的人.作为起点,请下载我的OpenGL Xcode项目模板,而不要使用Apple提供的模板.你可以 ...
- selenuim,qtp,loadrunner,jmeter有何区别,想学个脚本语言python和测试工具应该从哪里入门呢。
selenium和qtp是 功能的自动化测试,loadrunner和jmeter是性能的自动化测试 selenium要求代码能力比较高,适合用python,QTP一般用VBS,loadrunner一般 ...
- 指针--摘自C++技术网 作者dx
“指针是什么?”“指针就是一种数据类型.”“你确定?”“那数据类型是什么?额,这个???类型就是类型,还能怎么解释嘛.”“指针有多少种?”“指针有好多种,比如整型指针,字符指针等等.”“指针是怎么确定 ...
- 43个优秀的Swift开源项目推荐(转载)
["轮子"] 工具类 SwiftyJSON:GitHub 上最为开发者认可的 JSON 解析类 Dollar.swift:Swift 版 Lo-Dash (或 underscore ...
- Android Security
Android Security¶ 确认签名¶ Debug签名: $ jarsigner -verify -certs -verbose bin/TemplateGem.apk sm 2525 Sun ...
- psy & obv
PSY和OBV 1,PSY心理线是投资者对股市涨跌产生心理波动的情绪指标.相反,当PSY曲线向下跌破PSYMA曲线后,为卖出时机..当PSY曲线向上突破PSYMA曲线后,开始向下回调至PSYMA曲线, ...
- C++Builder String 转 char* (转)
源:http://blog.csdn.net/bannico/article/details/7577728 使用C++ Builder 处理字符串经常会遇到兼容性问题. 这次要将String 类型 ...
- Why attitude is more important than IQ
原文:http://www.businessinsider.com/why-attitude-is-more-important-than-iq-2015-9?IR=T& LinkedIn I ...
- docker 1.12 版本 docker swarm 集群
博客已经迁移到 个人博客中 个人博客 更新地址: http://www.xf80.com/2016/10/25/docker-swarm-1.12/ docker 1.12 版本 的新特性 (1)do ...
- Android学习笔记之Intent
Intent是Activity之间的管道 可以用来做Acitivity的跳转或传递数据 protected void onCreate(Bundle savedInstanceState) { sup ...