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 ...
随机推荐
- #ifndef 和 #endif
文件中的#ifndef 头件的中的#ifndef,这是一个很关键的东西.比如你有两个C文件,这两个C文件都include了同一个头文件.而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了, ...
- Android Studio相关的坑
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...
- update set from where
原文链接:http://blog.csdn.net/xcbsdu/article/details/6736503 关于update set from where 下面是这样一个例子: 两个表a.b,想 ...
- ONES 安装、配置以及初始化配置
环境依赖 bower composer php 5.5.9+ mysql 5.6.5+ PHP和MySQL版本均为最低要求版本,安装前请先确认. 通过CLI安装 $ git clone http:// ...
- Photoshop学习之路
网易云课堂中有的提升课程:http://study.163.com/course/courseMain.htm?courseId=765016&6925ecaa9614a750=Individ ...
- STL笔记之set
//---------------------------------------------------------// set综述//------------------------------- ...
- MQ日常维护操作手册
假设队列管理器为QMgrName,以下所有使用QMgrName的地方您都可以替换成您维护的mq队列管理器名称. 一.MQ的启动与停止 用root用户启/停需要root用户包含在mqm组中. 1.MQ的 ...
- Linux查看文件最后几行的命令,日志的福音啊
tail -n 20 filename说明:显示filename最后20行
- tcp 的6个控制位
原文:http://blog.chinaunix.net/uid-26413668-id-3376762.html TCP(Transmission Control Protocol) 传输控制协议 ...
- PAT (Advanced Level) 1046. Shortest Distance (20)
处理一下前缀和. #include<iostream> #include<cstring> #include<cmath> #include<algorith ...