在可剥夺性的内核中,当任务以独占方式使用共享资源的时候,会出现低优先级任务高于高优先级任务运行的情况,这种情况叫做优先级反转,对于实时操作系统而言,这是一场灾难,下面我们来说说优先级反转的典型环境.

我们假设有三个任务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互斥信号量解决优先级反转问题的更多相关文章

  1. ucos之互斥信号量及优先级反转

    在ucos常使用共享资源来作为任务之间的通信方式,其中有:消息队列,信号量,邮箱,事件.信号量中又分二值信号,多值信号,互斥信号.这次主要讲二值信号与互斥信号之间区别和使用. 首先了解一下ucos的任 ...

  2. UCOSIII互斥信号量

    互斥信号量可以解决优先级反转问题 优化后现象 优化方法:L和H等待同一个信号量的时候,将L任务优先级提至H相同优先级 实验举例 void start_task(void *p_arg) { OS_CR ...

  3. 【原创】xenomai内核解析--同步互斥机制(一)--优先级倒置

    版权声明:本文为本文为博主原创文章,转载请注明出处.如有错误,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ 目录 一.xenomai 资源管理简要 二.优先级倒 ...

  4. 【freertos】011-信号量、互斥量及优先级继承机制源码分析

    目录 前言 11.1 任务同步 11.2 信号量概念 11.3 二值信号量 11.3.1 二值信号量概念 11.3.2 优先级翻转 11.3.3 二值信号量运作机制 11.4 计数信号量 11.4.1 ...

  5. 【C# 线程】优先级反转与优先级继承

    什么是优先级反转(翻转)优先级反转,是指在使用信号量时,可能会出现的这样一种不合理的现象,即:    高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度.但其他中等优先级的任务却能抢到CP ...

  6. 优先级反转实验,使用信号量实现【RT-Thread学习笔记 5】

    RTOS中很经典的问题.就是在使用共享资源的时候,优先级低的进程在优先级高的进程之前执行的问题.这里模拟这种情况. 下面的实验模拟了优先级反转的情况: 先定义三个线程: //优先级反转实验 rt_se ...

  7. 【iCore4 双核心板_uC/OS-II】例程七:互斥信号量

    一.实验说明: 在介绍互斥信号量前,我们先简单地描述一下什么是优先级反转.使用实时内核心,优先级反转问题是实时系统中出现得最多的问题.假设任务H优先级高于任务M,任务M优先级高于任务L.任务H和任务M ...

  8. UCOSIII优先级反转

    反转现象 任务优先级:H>M>L 绿色部分:任务占用共享资源 理想状态:7释放信号量后,最高优先级H任务抢占CPU 反转原因:H和L等待同一个信号量,H的任务优先级被降至和L相同优先级,此 ...

  9. RTX——第15章 互斥信号量

    以下内容转载自安富莱电子: http://forum.armfly.com/forum.php 本章节开始讲解 RTX 的另一个重要的资源共享机制---互斥信号量(Mutex,即 Mutual Exc ...

随机推荐

  1. 指针--摘自C++技术网 作者dx

    “指针是什么?”“指针就是一种数据类型.”“你确定?”“那数据类型是什么?额,这个???类型就是类型,还能怎么解释嘛.”“指针有多少种?”“指针有好多种,比如整型指针,字符指针等等.”“指针是怎么确定 ...

  2. Mysql主从备份、主主备份

    简单介绍mysql双机,多机异地热备简单原理实战. 双机热备的概念简单说一下,就是要保持两个数据库的状态自动同步.对任何一个数据库的操作都自动应用到另外一个数据库,始终保持两个数据库数据一致. 这样做 ...

  3. CentOS6下配置Django+Apache+mod_wsgi+Sqlite3过程

    0. 安装环境: CentOs版本:      VMWare中CentOs 6.4 Apache版本:      Httpd 2.2.15 http://httpd.apache.org/ Sqlit ...

  4. Universal-Image-Loader分析:

    Android-Universal-Image-Loader是一个开源的UI组件程序,该项目的目的是提供一个可重复使用的仪器为异步图像加载,缓存和显示.权限: <uses-permission ...

  5. 动态规划3-------poj1050

    首先还是对题目的意思进行说明,给出一个矩阵的数,然后求出一个子矩阵这个子矩阵包含的数的和是最大的.   首先对于题目进行转化,利用一个数组add进行存放临时数据,第一行存放原来数据的第一行,第二行存放 ...

  6. 剑指offer 栈的压入弹出 顺序

    判断: 如果下一个弹出的数字刚好是栈顶元素,那么直接弹出 如果下一个弹出的数字不在栈顶,我们要把压栈序列中,还没有入栈的数字压入辅助栈,知道把下一个需要弹出的数字压入栈顶 如果所有的数字都入栈,但是仍 ...

  7. Android的Activity跳转动画各种效果整理

    Android的Activity跳转就是很生硬的切换界面.其实Android的Activity跳转可以设置各种动画,本文整理了一些,还有很多动画效果,就要靠我们发挥自己的想象力 大家使用Android ...

  8. 我也谈javascript闭包的原理理解

    参考原文:http://www.oschina.net/question/28_41112 前言:还是一篇入门文章.Javascript中有几个非常重要的语言特性——对象.原型继承.闭包.其中闭包 对 ...

  9. gen_compile.sql

    set echo off pagesize 0 feedback off define v_input_un       = &1define v_input_pw       = & ...

  10. UISegmentedControl 踩坑

    @interface JLMyContactsViewController () @property (nonatomic, strong)   UIImageView *navImageView; ...