ossempendubuntu 一直等待安装,什么时候进行任务切换

温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(638)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'ucos接口函数详解',
blogAbstract:'第六章& 事件控制块
任务或中断服务程序可以通过事件控制块(ECB)向另外的任务发信号,这里的信号被看成是事件。(1)中断服务程序不能等待事件控制块给它发送信号;(2)处于等待状态状态的任务可以设置等待超时;(3)多个任务同时等待一事件的发生,当事件发生时,只有优先级最高的任务得到该事件并进入就绪状态;
Ucosii通过ucos_ii.h中定义的OS_EVENT数据结构,维护一个事件控制块ECB的所有信息。该结构中除了包含事件本身的定义外,还定义了等待该事件的所有任务列表。每个信号量、互斥型信号量、消息邮箱、消息队列都应分配到一个事件控制块。
600 将任务置于等待事件的任务列表
Pevent-&OSEventGrp |= OSMapTbl[prio&&3];',
blogTag:'ucos,api',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:0,
publishTime:1,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}当前位置: >>
uCOS-II 入门理解
uCOS-II 初级程序员指南(一) uC/OS-II 简介uC/OS-II 是一种基于优先级的可抢先的硬实时内核.自从92年发布以来,在世界各地都获得 了广泛的应用,它是一种专门为嵌入式设备设计的内核,目前已经被移植到40多种不同结构的 CPU 上,运行在从8位到64位的各种系统之上. 尤其值得一提的是,该系统自从2.51 版本之后,就通过了 美国 FAA 认证,可以运行在诸如航天器等对安全要求极为苛刻的系统之上.鉴于 uC/OS-II 可以免费 获得代码,对于嵌入式 RTOS 而言,选择 uC/OS 无疑是最经济的选择.(二) uC/OS-II 应用程序基本结构应用 uC/OS-II,自然要为它开发应用程序,下面论述基于 uC/OS-II 的应用程序的基本结构以及注意 事项. 每一个 uC/OS-II 应用至少要有一个任务.而每一个任务必须被写成无限循环的形式.以下是推荐的 结构: void task ( void* pdata ) { INT8U InitTimer(); // 可选 For( ;; ) { // 你的应用程序代码 ……. …….. OSTimeDly(1); // 可选 } } 以上就是基本结构,至于为什么要写成无限循环的形式呢?那是因为系统会为每一个任务保留一 个堆栈空间,由系统在任务切换的时候换恢复上下文,并执行一条 reti 指令返回. 如果允许任务执行到 最后一个花括号(那一般都意味着一条 ret 指令)的话,很可能会破坏系统堆栈空间从而使应用程序 的执行不确定.换句话说,就是&跑飞&了.所以,每一个任务必须被写成无限循环的形式.程序员一定 要相信,自己的任务是会放弃 CPU 使用权的,而不管是系统强制(通过 ISR)还是主动放弃(通过调用 OS API). 现在来谈论上面程序中的 InitTimer()函数,这个函数应该由系统提供,程序员有义务在优先级最 高的任务内调用它而且不能在 for 循环内调用. 注意,这个函数是和所使用的 CPU 相关的,每种系统都 有自己的 Timer 初始化程序.在 uC/OS-II 的帮助手册内,作者特地强调绝对不能在 OSInit()或者 OSStart()内调用 Timer 初始化程序,那会破坏系统的可移植性同时带来性能上的损失. 所以,一个折 中的办法就是象上面这样,在优先级最高的程序内调用,这样可以保证当 OSStart()调用系统内部函 数 OSStartHighRdy()开始多任务后,首先执行的就是 Timer 初始化程序. 或者专门开一个优先级最 高的任务,只做一件事情,那就是执行 Timer 初始化,之后通过调用 OSTaskSuspend()将自己挂起来, 永远不再执行.不过这样会浪费一个 TCB 空间.对于那些 RAM 吃紧的系统来说,还是不用为好.(三) 一些重要的 uC/OS-II API 介绍任何一个操作系统都会提供大量的 API 供程序员使用,uC/OS-II 也不例外.由于 uC/OS-II 面 向的是嵌入式开发,并不要求大而全,所以内核提供的 API 也就大多和多任务息息相关. 主要的有以下 几类: 1)任务类 2)消息类 3)同步类 4)时间类 5)临界区与事件类 我个人认为对于初级程序员而言,任务类和时间类是必须要首先掌握的两种类型的 API.下面我就来 介绍比较重要的: 1) OSTaskCreate 函数 这个函数应该至少再 main 函数内调用一次,在 OSInit 函数调用之后调用.作用就是创建一个任务. 目前有四个参数,分别是任务的入口地址,任务的参数,任务堆栈的首地址和任务的优先级. 调用本函数 后,系统会首先从 TCB 空闲列表内申请一个空的 TCB 指针,然后将会根据用户给出参数初始化任务堆 栈,并在内部的任务就绪表内标记该任务为就绪状态.最后返回,这样一个任务就创建成功了. 2) OSTaskSuspend 函数 这个函数很简单,一看名字就该明白它的作用,它可以将指定的任务挂起. 如果挂起的是当前任务的话, 那么还会引发系统执行任务切换先导函数 OSShed 来进行一次任务切换.这个函数只有一个参数,那 就是指定任务的优先级.那为什么是优先级呢?事实上在系统内部,优先级除了表示一个任务执行的 先后次序外,还起着分别每一个任务的作用,换句话说,优先级也就是任务的 ID.所以 uC/OS-II 不允 许出现相同优先级的任务. 3) OSTaskResume 函数 这个函数和上面的函数正好相反,它用于将指定的已经挂起的函数恢复成就绪状态.如果恢复任务的 优先级高于当前任务,那么还为引发一次任务切换.其参数类似 OSTaskSuspend 函数,为指定任务 的优先级.需要特别说明是,本函数并不要求和 OSTaskSuspend 函数成对使用. 4) OS_ENTER_CRITICAL 宏 很多人都以为它是个函数,其实不然,仔细分析一下 OS_CPU.H 文件,它和下面马上要谈到的 OS_EXIT_CRITICAL 都是宏.他们都是涉及特定 CPU 的实现.一般都被替换为一条或者几条嵌入 式汇编代码.由于系统希望向上层程序员隐藏内部实现,故而一般都宣称执行此条指令后系统进入临 界区.其实,它就是关个中断而已.这样,只要任务不主动放弃 CPU 使用权,别的任务就没有占用 CPU 的机会了,相对这个任务而言,它就是独占了.所以说进入临界区了.这个宏能少用还是少用,因为它会 破坏系统的一些服务,尤其是时间服务.并使系统对外界响应性能降低. 5) OS_EXIT_CRITICAL 宏 这个是和上面介绍的宏配套使用另一个宏,它在系统手册里的说明是退出临界区.其实它就是重新开 中断.需要注意的是,它必须和上面的宏成对出现,否则会带来意想不到的后果.最坏的情况下,系统会 崩溃.我们推荐程序员们尽量少使用这两个宏调用,因为他们的确会破坏系统的多任务性能. 6) OSTimeDly 函数 这应该程序员们调用最多的一个函数了,这个函数完成功能很简单,就是先挂起当起当前任务,然后进 行任务切换,在指定的时间到来之后,将当前任务恢复为就绪状态,但是并不一定运行,如果恢复后是优 先级最高就绪任务的话,那么运行之.简单点说,就是可以任务延时一定时间后再次执行它,或者说,暂 时放弃 CPU 的使用权.一个任务可以不显式的调用这些可以导致放弃 CPU 使用权的 API,但那样多 任务性能会大大降低,因为此时仅仅依靠时钟机制在进行任务切换.一个好的任务应该在完成一些操 作主动放弃使用权,好东西要大家分享嘛!(四) uC/OS-II 多任务实现机制分析前面已经说过,uC/OS-II 是一种基于优先级的可抢先的多任务内核.那么,它的多任务机制到底 如何实现的呢?了解这些原理,可以帮助我们写出更加健壮的代码来.由于我们面向的初级程序员,本 文不打算写成又一篇 uC/OS-II 的源码分析,那样的文章太多了,本文打算从实现原理的角度探讨这个 问题. 首先我们来看看为什么多任务机制可以实现?其实在单一 CPU 的情况下,是不存在真正的多任务机制 的,存在的只有不同的任务轮流使用 CPU,所以本质上还是单任务的.但由于 CPU 执行速度非常快, 加上任务切换十分频繁并且切换的很快,所以我们感觉好像有很多任务同时在运行一样.这就是所谓 的多任务机制. 由上面的描述,不难发现,要实现多任务机制,那么目标 CPU 必须具备一种在运行期更改 PC 的途径,否 则无法做到切换. 不幸的使,直接设置 PC 指针,目前还没有哪个 CPU 支持这样的指令. 但是一般 CPU 都允许通过类似 JMP,CALL 这样的指令来间接的修改 PC.我们的多任务机制的实现也正是基于这个 出发点.事实上,我们使用 CALL 指令或者软中断指令来修改 PC,主要是软中断.但在一些 CPU 上, 并不存在软中断这样的概念,所以,我们在那些 CPU 上,使用几条 PUSH 指令加上一条 CALL 指令来模 拟一次软中断的发生. 回想一下你在微机原理课程上学过的知识,当发生中断的时候,CPU 保存当前的 PC 和状态寄存器的值 到堆栈里,然后将 PC 设置为中断服务程序的入口地址,再下来一个机器周期,就可以去执行中断服务程 序了.执行完毕之后,一般都是执行一条 RETI 指令,这条指令会把当前堆栈里的值弹出恢复到状态寄 存器和 PC 里.这样,系统就会回到中断以前的地方继续执行了.那么设想一下?如果再中断的时候, 人为的更改了堆栈里的值,那会发生什么?或者通过更改当前堆栈指针的值,又会发生什么呢?如果 更改是随意的,那么结果是无法预料的错误.因为我们无法确定机器下一条会执行些什么指令,但是如 果更改是计划好的,按照一定规则的话,那么我们就可以实现多任务机制. 事实上,这就是目前几乎所有 的 OS 的核心部分.不过他们的实现不像这样简单罢了. uC/OS-II v2.52 学习摘要(一) 学习摘要 一特别声明:本笔记是对 uc/os-ii 研究做一些重要的内核思路整理和心得记录,以日期为 作为记录块,故没有思路和规范可言,为此贴于工程师笔记里面,一来方便自己温故知新, 二来希望能给初学者带来一些方便和帮助.高手别见笑^_^,偶刚起步.另外,如有错误和 不当之处,请指正和发表您的心得体会.谢谢!
1. 任务是一个无返回的无穷循环.uc/os-ii 总是运行进入就绪状态的最高优先级的任务. 2. 任务是如何调度(切换)的? 因为 uc/os-ii 总是运行进入就绪状态的最高优先级的任务. 所以, 确定哪个任务优先级最高, 下面该哪个任务运行,这个工作就是由调度器(scheduler)来完成的. 任务级的调度是由函数 OSSched()完成的,而中断级的调度是由函数 OSIntExt()完成.对于 OSSched(),它内部调用的是 OS_TASK_SW()完成实际的调度(人为模仿一次中断) ; OSIntExt()内部调用的是 OSCtxSw()实现调度.参考:P92,P106 任务切换其实很简单,由如下 2 步完成: (1)将被挂起任务的处理器寄存器推入自己的 任务堆栈. (2) 然后将进入就绪状态的最高优先级的任务的寄存器值从堆栈中恢复到寄存器 中.参见 P92 (1) 作为 uc/os-ii 的一条普通原则, 调用 uc/os-ii 功能函数时, 中断总应当是开着的. (2)任务永不返回,就算任务自我删除,也绝对不会返回. (任务删除并非代码删 除,只是 ucos-ii 不会理会这任务. ) (3)OSTimeTick()函数是 ucos-ii 内部函数,用户无需调用. (4) ucos-ii 从中断返回之前, 要判断被中断的任务是否还是就绪状态任务中优先级 最高的任务.3. OSInit()初始化示意图 我做了一个很好的图示,竟然粘贴不出来,没办法... 4. 任务的 5 种状态 参见 P79 图 睡眠态(task dormat):任务驻留于程序空间(rom 或 ram)中,暂时没交给 ucos-ii 处理. 就绪态(task ready) :任务一旦建立,这个任务就进入了就绪态. 运行态(task running) :调用 OSStart()可以启动多任务.OSStart()函数只能调用一次, 一旦调用,系统将运行进入就绪态并且优先级最高的任务. 等待状态(task waiting) :正在运行的任务,通过延迟函数或 pend(挂起)相关函数后,将 进入等待状态. 中断状态(ISR running) :正在运行的任务是可以被中断的,除非该任务将中断关闭或者 ucos-ii 将中断关闭. 5. 任务控制块(OS_TBC) 任务一旦建立,任务控制块 OS_TBC 将被赋值. OS_TBC 是一个数据结构,当任务的 CPU 使用权被剥夺后,ucos-ii 将把当前的任务状态存 放于 OS-TBC 数据结构中;当任务的 CPU 使用权得到恢复后,任务控制块能确保任务能从 被中断点那一点丝毫不差地继续执行. 每个任务都有自己的 OS_TBC 控制块,OS_TBC 的数量由 OS_MAX_TASK 决定,任务数量 少,当然 OS_TBC 占用 RAM 的空间就少. 所有的任务控制块 OS_TBC 都是放在任务控制块列表数组 OSTCBTbl[]中. ucos-ii 初始化 在 时,所有任务控制块 OS_TBC 都被链表连接成单向空任务链表. 注意:OS_TBC 全部驻留于 RAM 中. 6. 关于任务切换使用到的 OS_TASK_SW()函数,其中调用软中断实现寄存器的保持和 弹出.开始调用含软中断,ucos-ii 强制处理器保存 psw,pc 的当前值,最后通过执行中断返 回指令,pc 和 psw 的值装回到 cpu 中. 1.中断服务所做的事应尽量少做,应把大部分工作留给任务去做. 2.OSIntExit()和 OSSched()有点相似,但 OSIntExit()使中断 nestiing 减 1,而重新调度的条 件是:中断 nesting 和锁定 nesting 计算器(OSLockNesting)均为 0. 3.OS_TASK_SW()和 OSCtxSw()的区别:后者使用于中断服务程序中,中断返回已经对 cpu 做了保存工作.而前者需要采用模仿软中断返回指令实现 cpu 保存. 4.时钟节拍 (1) ucos-ii 需要提供周期性的信号源,用于实现时间延迟和确认超时.节拍率应为 10~100Hz,时钟节拍率越高,系统额外的负荷就越重. (2) 定时中断. 系统多任务启动时候(调用 OSStart())之后,第一件初始化事情就是初始化(3) ucos-ii 中的时钟节拍服务是通过在中断服务子程序(OSTickISR())中调用 OSTimeTick()实现的.OSTimeTick()跟踪所以任务的定时器和超时时限.时钟节拍中断服从 一般中断规则(含任务调度判断) . 5.OSTCBList 指向任务控制块链表的开始,而且它总是指向最新建立的任务. 6.非常好的一个图示:OSInt()之后的变量和数据结构.请参阅 P112 7.启动多任务时,执行 OSStart()函数,OSStart()先从任务就绪表中找出用户建立的优先级 最高的任务的任务控制块,而后调用了 OSStartHighRdy(),此函数实质上是将任务堆栈中的 保存内容返回到 cpu 寄存器中,然后执行一条中断返回指令. 【信号量专题】1. 信号量的理解 (1)uc/os-ii 的信号量是由两个部分组成:一部分是 16 位的无符号整型信号量的计数值 (0~65535); 另一部分是等待该信号量的任务组成的等待任务表. 另外参考事件控制块 ECB) ( (2)信号量可以是 2 值的变量(称为二值信号量) ,也可以是计数式的.根据信号量的值, 内核跟踪那些等待信号量的任务. (3)建立信号量的工作必须在任务级代码中或者多任务启动之前完成. (4)任务要得到信号量的问题. 想得到信号量的任务,必须执行等待操作(pend) .如果信号量有效(非 0),则信号量减 1, 任务得以继续运行. 如果信号量无效, 则等待信号量的任务就被列入等待信号量的任务表中. 多少内核允许定义等待超时,当等待时间超过了设定值,该信号量还是无效,则等待该信号 量的任务进入就绪态,准备运行,并返回出错代码(等待超时错误). (5)任务对信号量的释放问题. 任务执行发信号(post)操作来释放信号量.如果没有任务等待信号量,那么信号量的值仅 是简单的加 1(则信号量大于 0,有效) ;如果有任务等待该信号量,那么就会有另一个任务 进入就绪态,信号量的值就不加 1. 之后,这个释放的信号量给那个等待中的任务,要看内核如何调度的.收到信号量的任务可 能是如下两者之一: ◆等待任务中,优先级最高的; (uc/os-ii 仅支持这种方式) . ◆最早开始等待信号量的任务(如果是按先进先出 FIFO 原则) .2. 信号量的有效与无效问题 信号量有效:信号量的计算器非 0(.OSEventCnt!=0) .信号量有效表示任务对资源可用. 信号量无效:信号量的计算器为 0.信号量无效表示任务对目前资源不可用,需要等待其他 另一个任务(或者中断服务子程序)发出该信号量(OSSemPost) . 3. 信号量的值(.OSEventCnt)大小表示什么? 二值信号量,表示任务可以独占共享资源. 计数式信号量,用于某资源可同时为 N 个任务所用. 4. 信号量是如何实现任务之间的通信的? 参见第 1 点的(4)(5)概述. 5. 信号量有关的三个重要函数分析 ◆OSSemCreate() 创建一个信号量 (注:由任务或启动代码操作) 创建工作必须在任务级代码中或者多任务启动之前完成. 功能只要是先获取一个事件控制块 ECB,写入一些参数.其中调用了 OS_EeventWaitListInt()函数,对事件控制块的等待任务列 表进行初始化.完成初始化工作后,返回一个该信号量的句柄(Handle).◆OSSemPend() 等待一个信号量 (注:只能由任务操作) 本函数应用于任务试图获得共享资源的使用权, 任务需要与其他任务或中断同步及任务需要 等待特定事件发生的场合. 如果任务 Task_A 调用 OSSemPend(), 且信号量的值有效(非 0), 那么 OSSemPend()递减信号 量计数器(.OSEventCnt) ,并返回该值.换句话说,Task_A 获取到共享资源的使用权了, 之后就执行该资源. 如果如果任务 Task_A 调用 OSSemPend(),信号量无效(为 0),那么 OSSemPend()调用 OS_EventTaskWait() 函 数 , 把 Task_A 放 入 等 待 列 表 中 . 等 待 到 什 么 时 候 呢 ? 要 看 ( OSSemPost()(或者等待超时情况),由它释放信号量并检查任务执行权,见下资料)◆OSSemPost() 发出(释放)一个信号量 (注:由任务或中断操作) 本函数其中调用 OS_EventTaskRdy()函数, 把优先级最高的任务 Task_A (在这假如是 Task_A, 另外假设当前调用 OSSemPost()的任务是 Task_B) 从等待任务列表中去除, 并使它进入就绪 态.然后调用 OSSched()进行任务调度.如果 Task_A 是当前就绪态中优先级最高的任务, 则内核执行 Task_A;否则,OSSched()直接返回,Task_B 继续执行. 互斥型信号量 1.互斥型信号量(mutex) 互斥型信号量具备 uc/os-ii 信号量的所有机制,但还具有其他一些特性. 任务可利用互斥型信号量来实现对共享资源的独占处理. Mutex 是二值信号量,1 表示资源是可以使用的.2.关于优先级反转 下面概述优先级反转原理: 假设有三个任务,分别命名为 A,B,C;A 的优先级最高,C 的优先级最低.任务 A 和任务 B 处于挂起状态(请注意这条件),等待某一事件的发生,任务 C 正在运行.当任务 C 等待到共享资源(命名为 S1)并使用后,如果任务 A 等待得事件到来之后,由于 A 的优先 级最高,所以就会剥夺任务 C 的 CPU 使用权.运行过程中,任务 A 也要使用资源 S1,但 S1 的信号量还被任务 C 占用着,所有任务 A 只能进入挂起状态,等待任务 C 对 S1 的信号 量的释放.此时任务 C 得以继续运行. 同理,任务 B 的事件到来后,会剥夺任务 C 的 CPU 使用权.任务 B 把事情搞定以 后,把 CPU 使用权归还给任务 B(呵呵,优先级低就是给人欺负啊,所以做人还真的要争 口气!.任务 B 又得以继续运行,任务 B 认真处理完毕资源 S1 后,终于可以释放 S1 的信 ) 号量.而处于等待该信号量的任务 A 马上得到信号量并开始处理共享资源 S1. 综述上面情况,任务 C 和任务 A 的优先级发生了反转. 而互斥型信号量就是具有解决优先级反转问题的特性. 3.uc/os-ii 的互斥型信号量由三个部分组成: ◆一个标志,指示 mutex 是否可以使用(0 或 1) ◆一个优先级,准备一旦高优先级的任务需要这个 mutex,赋予给占有 mutex 的任务. ◆一个等待该 mutex 的任务列表.
更多搜索:
All rights reserved Powered by
文档资料库内容来自网络,如有侵犯请联系客服。 上传我的文档
 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
正在努力加载中...
任务的同步与通信
下载积分:2500
内容提示:任务的同步与通信
文档格式:PPT|
浏览次数:7|
上传日期: 22:16:44|
文档星级:
全文阅读已结束,如果下载本文需要使用
 2500 积分
下载此文档
该用户还上传了这些文档
任务的同步与通信
关注微信公众号μC-OS-III对信号量的改进_文档库
文档库最新最全的文档下载
当前位置: & μC-OS-III对信号量的改进
μC-OS-III对信号量的改进
μC/OS-III对信号量的改进
引言&C/OS 是一个基于优先级调度的可剥夺型实时多任务内核。在多任务的实时内核中,信号量是常用的机制,可以用来实现对共享资源的访问、任务之间的通信和同步,以及任务和中断的同步等功能。&C/OS&II中提供了等待和释放信号量等最基本的服务,而在&C/OS&III中,对信号量的使用增加了一些可选的模式,如非阻塞等待、释放但不进行任务调度等,提高了使用的灵活性。更重要的是,在&C/OS&III中还新增了任务内嵌的信号量,用户程序无需建立信号量便可和任务直接通信,比普通信号量更加简单高效。本文将分析对比&C/OS&II和&C/OS&III中信号量内部结构的差异以及&C/OS&III新增的特性。1 &C/OS&II中信号量内部结构在&C/OS&II中,信号量直接使用内核的数据结构OS EVENT,其内部结构如下:其中,和信号量相关的最重要的就是OSEventCnt 、OSEventGrp 和OSEventTbl[]。OSEventCnt 记录的是信号量的有效值。OSEventTbl[]是一个位映射表,以64级优先级为例,OSEventTbl[]将是一个8&8的位映射表,如果某优先级下有任务在等待该事件,则OSEventTbl[]中对应的位将被置1。为了加快查询过程,又将64级优先级分为8组,用一个8位的整型OSEventGrp 来记录每一组的状态。可见,OSEventGrp 和OSEve ntTbl[]跟就绪表中的OSRdyGrp 和OSRdyTbl[]结构是一模一样的,区别仅仅在于前者记录的是等待该事件的任务的状态,而后者记录的是系统中就绪的任务的状态。而两者的查找过程是一样的,都是通过&掩码表&来快速得到列表中优先级最高的任务。&C/OS&II提供的信号量相关的最常用的几个API 函数如下:在使用信号量前必须先新建一个信号量,并指定其初始值。当信号量用于对共享资源的访问时,该值应初始化为实际可用的共享资源数;当信号量用来实现任务的同步,则初始值应设为0。调用等待信号量的OSSemPend()函数时可以指定超时选项timeout ,在指定的时间内如果没有获得信号量则任务会超时返回。释放信号量时,如果有任务在等待,内核会通过查找OSEventGrp 和OSEventTbl[]获得等待任务中优先级最高的任务,该任务将获得信号量从而转入就绪态,内核会进行任务调度。如果获得信号量的任务比正在执行的任务优先级还高,则会进行任务切换。2 &C/OS-Ⅲ中信号量内部结构在&C/OS&III中,信号量类型的结构有所变化,并没有和&C/OS&II一样继续采用和&就绪表&类似的结构,而是采用一个&等待列表&的数据结构来记录等待信号量的任务。其数据结构如下:从上述结构可以看出,&C/OS&III的信号量结构中新增了一个时间戳TS ,用来记录最近一次释放信号量(或者是取消等待、删除信号量) 的时间。而等待信号量的任务列表则通过一个新的数据结构OS_PEND_LIST来记录,。
OS_PEND_LIST包括3个数据域:NbrEntries 用来记录等待列表中的条目数,也就是等待的任务数目;HeadPtr 和TailPtr 构成一个双向链表,指向的是OS_PEND_DATA类型的结构体。OS_PEND_DATA是&C/OS&III内部的一个数据类型,每当任务因等待信号量而被挂起时,内核就会新建一个对应的OS_PEND_DATA类型的数据块并插入到信号量的等待列表OS_PEND_LIST所包含的双向链表中。OS_PEND_DATA结构体包含指向等待任务的OS_TCB的指针以及其他数据域。在这里,最重要的细节是,&C/OS-III 是按照任务优先级从高到低的顺序来排列双向链表中的OS_PE ND_DATA数据块的。也就是说,每当有一个新的OS_PEND_DATA数据块需要插入到双向链表时(也就是任务因等待信号量而被挂起时) ,内核会从链表头部开始扫描各个OSPEND_DATA数据块所对应的等待任务的优先级(通过OS_PEND_DATA数据块内部的TCBPtr 指针可以从任务控制块内部获得任务的优先级) ,直到找到比当前需要插入的任务的优先级低的任务,然后把新的OS PEND_DATA数据块插入到该位置前。如果链表中已有和需要插入的任务优先级相同的任务,则新插入的任务放到优先级相同的任务后。道理很简单,优先级相同,晚到的任务没有任何理由比早到的任务先获得信号量。基于上述排列方法,位于双向链表头部的任务总是等待的任务中优先级最高的。因此,当用户释放信号量时,总是双向链表头部的任务获得信号量,而不必再执行&查找最高优先级&的过程了。&C/OS&III提供的信号量相关的最常用的几个API 函数如下:OSSemCreate()函数和&C/OS&II中的类似,需要指定信号量的初始值,还需额外指定信号量的名称以便于调试。OSSemPend()函数多了两个参数:opt 和p_ts。p_ts是指向时间戳的指针,当任务获得信号量(或者任务取消等待或信号量被删除) 返回时,内核会把释放信号量(或者任务取消等待或信号量被删除)
Word文档免费下载:

我要回帖

更多关于 xcode更新一直等待 的文章

 

随机推荐