uCOSII实时操作系统通信机制之内核分析

合集下载

uCOS原理及应用

uCOS原理及应用
周立功单片机
• 多任务系统工作原理
操作系统的调度程序对所有任务实现运行控制 调度程序对所有任务实现运行控制; 任务切换实际就是把当前任务所占用的CPU资源用其它任务来替 任务切换 换; CPU资源包括寄存器R0-R15、CPSR、SPRS和其它一些全局变量; 调度程序由系统节拍驱动 系统节拍驱动。
移植时需要 编写的代码
用于产生 系统时钟
周立功单片机
移植简介
• 概述
要移植 移植一个操作系统到一个特定的CPU体系结构 上并不是一件很容易的事情 并不是一件很容易的事情,它对移植者有以下要求: 1. 对目标体系结构要有很深了解; 2. 对OS原理要有较深入的了解; 3. 对所使用的编译器要有较深入的了解; 4. 对需要移植的操作系统要有相当的了解; 5. 对具体使用的芯片也要一定的了解。
栈底 任务环境开始
SP
周立功单片机
• 堆栈初始化函数
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) { OS_STK *stk; opt = opt; stk = ptos; *stk = (OS_STK) task; *--stk = (OS_STK) task; *--stk = 0; 栈底 任务入栈的 *--stk = 0; 其它数据 *--stk = 0; *--stk = 0; PC *--stk = 任务环境开始 0; LR *--stk = 0; R12 *--stk = 0; R11 *--stk = 0; R10 *--stk = 0; R9 *--stk = 0; R8 *--stk = 0; ... *--stk = 0; R2 *--stk = (unsigned int) pdata; R1 *--stk = (USER_USING_MODE|0x00); R0 *--stk = 0; OSEnterSum SP return (stk); 空闲空间 } 周立功单片机

ucosii 互斥信号量 创建条件

ucosii 互斥信号量 创建条件

ucosii 互斥信号量创建条件摘要:1.ucosii 简介2.互斥信号量的概念3.互斥信号量的创建条件4.互斥信号量在ucosii 中的应用正文:【1.ucosii 简介】ucosii是一款基于μC/OS-II实时操作系统的嵌入式软件开发平台。

μC/OS-II是一个源代码公开的实时操作系统内核,其主要特点是可移植性强、占用资源少、实时性能优越,适用于各种嵌入式系统。

ucosii在μC/OS-II的基础上,提供了丰富的组件和工具,便于开发者快速构建嵌入式系统。

【2.互斥信号量的概念】互斥信号量(Mutex)是一种同步原语,用于实现多任务之间的互斥访问。

互斥信号量有一个计数器,用于表示当前有多少任务正在访问共享资源。

当一个任务要访问共享资源时,需要先请求互斥信号量。

如果计数器为零,表示当前没有其他任务访问共享资源,请求信号量后计数器加一,任务可以访问共享资源;如果计数器大于零,表示其他任务正在访问共享资源,请求信号量后计数器加一,任务需要等待其他任务访问完成后才能访问共享资源。

任务访问完共享资源后,释放互斥信号量,计数器减一,表示可以有其他任务访问共享资源。

【3.互斥信号量的创建条件】在ucosii 中,创建互斥信号量需要满足以下条件:1.互斥信号量对象需要分配在用户空间,不能分配在内核空间。

2.互斥信号量对象的初始化需要保证计数器为零,表示没有任务访问共享资源。

3.互斥信号量对象需要关联一个等待队列,用于存放等待访问共享资源的任务。

【4.互斥信号量在ucosii 中的应用】在ucosii 中,互斥信号量可以用于保护共享资源,避免多任务同时访问导致的数据不一致问题。

以下是一个简单的互斥信号量使用示例:```c#include "ucosii.h"#include "ucosii_os.h"// 定义共享资源int32_t g_data;// 创建互斥信号量MUTEX_T g_mutex;// 初始化互斥信号量void init_mutex() {mutex_init(&g_mutex, 0);}// 访问共享资源void access_data() {int32_t i;for (i = 0; i < 10; i++) {// 获取互斥信号量mutex_lock(&g_mutex);// 访问共享资源g_data = i;// 释放互斥信号量mutex_unlock(&g_mutex);}}// 任务入口void app_main() {init_mutex();// 启动多个任务访问共享资源while (1) {task_create(1, access_data, NULL);}}```在这个示例中,我们定义了一个共享资源g_data,并创建了一个互斥信号量g_mutex。

VxWorks,uCOS II、RT-Linux、QNX大比拼

VxWorks,uCOS II、RT-Linux、QNX大比拼

VxWorks,uC/OS II、RT-Linux、QNX大比拼20世纪70年代以来嵌入式系统的硬件和软件技术的飞速进步,使得嵌入式应用得到了蓬勃发展,在这些应用中实时操作系统起着决定性的作用。

在复杂测控应用中,必须使用对实时性要求非常高的实时操作系统。

例如在工业控制、交通管理、机器人、航空航天、武器装备等领域,系统事件的响应如果不能准时或超时,就可能导致巨大的损失和灾难。

因而,选择操作系统时,对实时性的仔细考虑至关重要。

本文从实时性的角度细致的分析对比了适用于此类有苛刻实时性要求的 4 种操作系统——VxWorks、uC/OS II、RT-Linux、QNX,为系统选型提供一定参考。

实时性能主要实现技术实时操作系统的实时性是第一要求,需要调度一切可利用的资源完成实时任务。

根据响应时间在微秒、毫秒和秒级的不同,可分为强实时、准实时和弱实时三种。

强实时系统必须是对即时的事件作出反应,绝对不能错过事件处理时限。

例如测控领域就是要求强或接近强实时系统。

在机顶盒、PDA、信息家电等应用领域,系统负荷较重的时候,允许发生错过时限的情况而且不会造成太大的危害,准和弱实时系统就可满足应用。

一个强实时的操作系统通常使用以下技术:∙占先式内核当系统时间响应很重要时,要使用占先式内核。

当前最高优先级的任务一旦就绪,总能立即得到CPU 的控制权,而CPU 的控制权是可知的。

使用占先式内核使得任务级响应时间得以最优化。

∙调度策略分析任务调度策略是直接影响实时性能的因素。

强实时系统和准实时系统的实现区别主要在选择调度算法上。

选择基于优先级调度的算法足以满足准实时系统的要求,而且可以提供高速的响应和大的系统吞吐率。

当两个或两个以上任务有同样优先级,通常用时间片轮转法进行调度。

对硬实时系统而言,需要使用的算法就应该是调度方式简单,反应速度快的实时调度算法了。

尽管调度算法多种多样,但大多由单一比率调度算法(RMS)和最早期限优先算法(EDF)变化而来。

uCOSII的特点

uCOSII的特点

笔记一:µC/OS-II的特点µC/OS-II系统是专门为计算机的嵌入式应用而设计的。

µC/OS-II系统中90%的代码是用C语言编写的,CPU硬件相关部分是用汇编语言编写的。

总量约200行的汇编语言部分被压缩到最低限度,便于移植到任何一种其他CPU上,用户只需要有标准的ANSI的C交叉编译器,有汇编器、连接器等软件工具就可以将µC/OS-II系统嵌入到所要开发的产品中。

µC/OS-II系统具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点。

其主要特点如下:1)开源性。

µC/OS-II系统的源代码全部公开,用户可以直接登录µC/OS-II的官方网站下载,官方网站公布了针对不同微处理器的移植代码。

这样就使系统变得开放、透明,极大地方便了µC/OS-II系统的开发,提高了开发效率。

2)可移植性。

绝大部分µC/OS-II系统的源码是用移植性很强的ANSI C语句写的,和微处理器硬件部分相关的是用汇编语言写的。

µC/OS-II系统能够移植到多种微处理器的条件是只要该微处理器具有堆栈指针,有CPU内部寄存器入栈、出栈指令。

另外,使用的C编译器必须支持内嵌汇编(inline assembly)或者该C语言可扩展、可连接汇编模块,使得关中断、开中断能够在C语言程序中执行。

3)可固化。

µC/OS-II系统是为嵌入式应用而设计的,只要具备合适的软、硬件工具,µC/OS-II系统就可以嵌入到用户的产品中,成为产品的一部分。

4)可裁剪。

用户可以根据自身需求只使用µC/OS-II系统中应用程序中需要的系统服务,而且这种可裁剪性是依靠条件编译实现的,处理较方便。

5)抢占试。

µC/OS-II系统是完全抢占式的实时内核。

µC/OS-II系统总是运行就绪条件下优先级最高的任务。

uCOS-II ppt 入门基础

uCOS-II  ppt 入门基础

硬件初始化
• 系统启动处理(在调用uC/OS-II操作系统初始化函数 OSInit()前,需要对CPU进行必要的初始化,例如设置异 常处理栈空间。要使uC/OS-II能够正常运行,时钟任务是 必不可少的。另外,启动代码需要存储在哪个内存空间, 在运行时需要在哪个内存中运行,这些都需要程序员手动 设置。)
典型的main函数
• • • • • • • • • • • • • • void main (void) { /*-----硬件初始化,等用户代码初始化-----*/ ... OSInit(); /* 初始化uC/OS-II */ …/*-------安装中断向量---------*/ /*通过调用OSTaskCreate ( ) 或OSTaskCreateExt ( )创建至少一个任务;*/ OSTaskCreate(TaskStart , (void*)0, &TaskStartStk[TASK_STK_SIZE - 1], 2 ); … /*通过调用OSSemCreate() 创建信号量等任务通信方式;*/ CalcSem = OSSemCreate(0); … OSStart(); /* 开始多任务调度!OSStart()永远不会返回 */ }
时钟
PC机上移植和运行uC/OS-II要注意其与PC机中其他操 作系统的关系(主要是与DOS操作系统之间的关系),不 能因为安装了uC/OS-II而使其他操作系统不能正常使用。 • 在PC机中,DOS系统时间的周期为 54.93ms(18.20648HZ)。 • DOS操作系统的系统时钟是由PC机上配置的硬件定时 DOS PC 器产生的。在硬件定时器的每个定时周期结束时,硬件定 时器便向CPU申请一次中断,在中断服务程序中处理DOS 所需要的系统时钟,同时处理DOS系统有关时间的一些管 理事务。在80X86系统的中断向量表中,产生DOS系统时 钟硬件定时器所占用的中断向量为0x08. • 在这我们把uC/OS-II的系统时钟频率设置为200HZ,这 显然比DOS的时钟频率高得多。因此,借用产生的DOS系 统时钟的定时器信号来产生uC/OS-II系统时钟。200除于11 等于18.18约等于18.2.后把uC/OS-II的时钟中断向量安装到 0x08上,而把0x08中原来的DOS的时钟中断向量转存到中 •

嵌入式实时操作系统μCOS原理与实践1

嵌入式实时操作系统μCOS原理与实践1

4、文件管理:
对外存中信息进行管理的文件系统
关于μC/OS-II
•UCOSII 是一个可以基于ROM 运行的、可裁减的 、抢占式、实时多任务内核,具有高度可移植性, 特别适合于微处理器和控制器,是和很多商业操作 系统性能相当的实时操作系统(RTOS)。为了提供 最好的移植性能,UCOSII 最大程度上使用ANSI C 语言进行开发,并且已经移植到近40 多种处理器 体系上,涵盖了从8 位到64 位各种CPU(包括DSP) 。
• 事件
两个任务通过事件进行通讯的示意图所示:
注释:任务1 是发信方,任务2 是收信方。任务1 负责把信息发送到 时间上,这项操作叫做发送事件。任务2 通过读取事件操作对事件进 行查询,如果有信息则读取,否则等待。读事件操作叫做请求事件。
事件控制块(ECB)
• 为了把描述事件的数据结构统一起来,UCOSII 使用叫做事件控制 块(ECB)的数据结构来描述诸如信号量、邮箱(消息邮箱)和消息 队列这些事件。事件控制块中包含包括等待任务表在内的所有有关 事件的数据,事件控制块结构体定义如下: • typedef struct { INT8U OSEventType; //事件的类型 INT16U OSEventCnt; //信号量计数器 void *OSEventPtr; //消息或消息队列的指针 INT8U OSEventGrp; //等待事件的任务组 INT8U OSEventTbl[OS_EVENT_TBL_SIZE];//任务等待表 #if OS_EVENT_NAME_EN > 0u INT8U *OSEventName; //事件名 #endif } OS_EVENT;
UCOSII中与任务相关的几个函数
1) 建立任务函数

第7章 uCOS-II及应用开发


5个管理函数:
OSTimeDLY() 任务延时函数 OSTimeDLYHMSM() 按时分秒延时函数 OSTimeDlyResmue() 让处在延时期的任 务结束延时 OStimeGet() 系统时间 OSTimeSet()
4. 任务间的通信与同步
C/OS中,采用多种方法保护任务之间的共 享数据和提供任务之间的通信。
第七章 uC/OS-II操作系统概述
7.1 7.2
µ C/OS-Ⅱ介绍 µ C/OS-Ⅱ在S3C44B0X上的移植
7.1 µ C/OS-Ⅱ介绍
主要内容
简介 µ C/OS-Ⅱ的特点 µ C/OS-Ⅱ的内核 µ C/OS-Ⅱ的文件体系
一、µ C/OS-Ⅱ简介
µ C/OS-Ⅱ读作“micro controller OS 2”, 意为“微控制器操作系统版本2”。 系统特征之一是:结构小巧。包含全部 功能的核心部分代码只占用8.3K字节, 同时由于µ C/OS-Ⅱ是可裁剪的,所以用 户系统中实际的代码最少可达2.7K字节。
睡眠态(Dormant) 就绪态(Ready)
运行态(Running)
等待或挂起态(Waiting or Pending) 中断态(Interrupt)
睡眠态(DORMANT): 指任务驻留在程序空间之中,还没有交给 μ C/OS-Ⅱ管理。 把任务交给μ C/OS-Ⅱ是通过调用下述两个函数 之一:OSTaskCreate()或OSTaskCreateExt()。当任务 一旦建立,这个任务就进入就绪态准备运行。
二、µ C/OS-Ⅱ的特点
6. 多任务 µC/OS-Ⅱ可以管理64个任务,在目前的 版本中,系统保留了最高的4个优先级和 最低的4优先级任务,所以用户实际上最 多可以拥有56个任务。注意:系统赋给 每个任务的优先级必须不同。 7. 任务栈 µ C/OS-Ⅱ的每个任务都有自己单独的栈和 栈空间。

ucosii对于信号量,互斥信号量,事件标志组的个人理解

ucosii对于信号量,互斥信号量,事件标志组的个人理解ucos看了也有一周多了,索性源码都能开得懂,并且能去理解。

昨天一开始看事件标志组的时候确实不知道怎么回事,后来百度一下,明白了事件标志组的作用以后,再去看书上的讲解和原码就清晰多了,很容易就明白了他的基本运行机理。

这也给了我一点启示,学一个东西,看一个东西之前,你最少要知道他干嘛用的,如果连干嘛用的都知道书看的再熟也是枉然。

ucos中提供了好几个用于同步事件以及共享资源访问的机制,目前我看明白的有信号量,互斥信号量,事件标志组。

下面谈谈自己对他们的理解:1.互斥信号量:互斥互斥,意思就是我用了你就不能用,你用了我就不能用。

永远都只有一个人独占这个东西~!举个例子:比如说打印机。

我任务1现在让他打印《静夜思》,那么在我还没打印完之前,别的任务就不能命令打印机去打印别的东西。

否则如果任务2让他打印《春晓》,那最后打印出来的会是什么~????反正肯定不是任务1想要的,肯定也不是任务2想要的。

上面讲的比较通俗。

打印机就是共享资源,谁都可以访问他~!但是同一时间,肯定要保证只有1个任务再操作打印机。

那样才能得到大家想要的结果。

也就是要独占共享资源的访问权~!ucos2中通过互斥信号量来解决这个问题。

简单说就是任务1开始访问打印机的时候,先去查询这个互斥信号量是否有效,有效,说明没人在访问打印机,这时任务1就把这个互斥信号量置无效,然后开始操作打印机。

这样,每个任务再操作打印机前都要去查询这个互斥信号量时候有效。

无效就等,等到有效才可以访问,或者等到不耐烦了(术语叫等待超时)就不等了~!任务一直到用完了打印机后才把信号量置有效,这时其他任务才有可能去访问,操作打印机。

这里又有一个问题:再任务1操作打印机器件,可能有多个任务申请打印机的所有权。

那么再任务1结束后,我应该给谁用呢~~??也许我们马上就反应过来了~废话~!!当然是排队了~~谁先到的谁用啊~~~。

ucos-ii中文书(邵贝贝)第2章

第2章实时系统概念 (1)2.0 前后台系统(F OREGROUND/B ACKGROUND S YSTEM) (1)2.1 代码的临界段 (2)2.2 资源 (2)2.3 共享资源 (2)2.4 多任务 (2)2.5 任务 (3)2.6 任务切换(C ONTEXT S WITCH OR T ASK S WITCH) (4)2.7 内核(K ERNEL) (5)2.8 调度(S CHEDULER) (5)2.9 不可剥夺型内核(N ON-P REEMPTIVE K ERNEL) (5)2.10 可剥夺型内核 (6)2.11 可重入性(R EENTRANCY) (7)2.12 时间片轮番调度法 (9)2.13 任务优先级 (10)2.14 2.14静态优先级 (10)2.15 动态优先级 (10)2.16 优先级反转 (10)2.17 任务优先级分配 (12)2.18 互斥条件 (13)2.18.1关中断和开中断 (14)2.18.2测试并置位 (15)2.18.3禁止,然后允许任务切换 (15)2.18.4信号量(Semaphores) (16)2.19 死锁(或抱死)(D EADLOCK (OR D EADLY E MBRACE)) (21)2.20 同步 (21)2.21 事件标志(E VENT F LAGS) (23)2.22 任务间的通讯(I NTERTASK C OMMUNICATION) (24)2.23 消息邮箱(M ESSAGE M AIL BOXES) (25)2.24 消息队列(M ESSAGE Q UEUE) (26)2.25 中断 (27)2.26 中断延迟 (27)2.27 中断响应 (28)2.28 中断恢复时间(I NTERRUPT R ECOVERY) (29)2.29 中断延迟、响应和恢复 (29)2.30 中断处理时间 (30)2.31 非屏蔽中断(NMI) (31)2.32 时钟节拍(C LOCK T ICK) (33)I2.33 对存储器的需求 (35)2.34 使用实时内核的优缺点 (36)2.35 实时系统小结 (37)II1 第2章 实时系统概念实时系统的特点是,如果逻辑和时序出现偏差将会引起严重后果的系统。

嵌入式操作系统ucos与linux比较

ucos2与linux的比较随着嵌入式计算机技术的迅猛发展,嵌入式操作系统的应用领域逐步扩大,嵌入式计算机已经深入到人类日常生活和生产的各个角落。

这次通过阅读相关资料,进一步加深了对嵌入式操作系统的了解,以下着重对ucos2和linux进行比较,谈谈对嵌入式操作系统的理解。

首先linux和ucos都是免费使用,源代码公开的操作系统,可供用户自由进行裁剪,添加,移植。

Linux是分时多任务多用户操作系统,ucos是实时多任务操作系统。

两者都可运行于多种平台,适应性好,linux不仅可以运行于32位机,也可运行于64位机,单核,多核也同样适用。

uCOS 2已经移植到近40多种处理器体系上,涵盖了从8位到64位各种CPU(包括DSP)。

内核Ucos内核包括操作系统初始化、操作系统运行、中断进出的前导、时钟节拍、任务调度、事件处理等多部分,能够维持系统基本工作的部分都在这里。

而linux内核包括进程管理,内存管理,设备管理,网络管理四部分。

Ucos没有提供输入输出管理,文件系统,网络等服务。

这些功能可由用户自行添加实现。

Ucos内核支持抢占,即在进行内核服务函数时,允许被中断服务中断,并且中断结束后可以重新进行任务调度。

Linux是非抢占式内核,实时性差。

当进程运行在用户态时,可以被优先级更高的进程抢占,但当他进入核心态时,优先级再高也不能抢占它。

实时性实时任务分为软实时和硬实时,硬实时对响应时间要求较高,且时间不被满足时会导致致命的错误,软实时随对响应时间有要求,但不是强制,不会给系统造成致命错误。

Ucos是一个基于优先级调度的抢占式的实时内核,不仅内核支持抢占,同时支持任务的抢占式调度,优先级低的任务可以被高优先级任务抢占,也可被中断服务抢占。

这就保证了系统可以尽可能快的对外部事件做出响应。

通用Linux主要考虑调度的公平性和吞吐量等指标,尽管系统可以通过把实时事件赋予高优先级的方法来实时响应实时事件,但效果有限,对于响应时间要求比较高的硬实时任务,无法满足要求。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

μC/OS-II通信机制之内核分析摘要:本文主要着重对μC/OS-III通信机制的内核分析,研究μC/OS-II内核通信机制的实现方式及实现的技巧,同时分析其中不足之处。

1.引言μC/OS-II是一种可移植的,可植入ROM的,可裁剪的,抢占式的,实时多任务操作系统内核。

它被广泛应用于微处理器、微控制器和数字信号处理器。

uC/OS-II只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。

没有提供输入输出管理,文件系统,网络等额外的服务。

但由于uC/OS-II良好的可扩展性和源码开放,这些非必须的功能完全可以由用户自己根据需要分别实现。

μC/OS-II这款操作系统内核简单易学,通过对其源代码的分析,可以加深我们对操作系统内核的理解,为学习linux等大型操作系统打下基础。

2.操作系统中任务间的通信机制内核中多个任务之间不可避免的存在相互协同的关系,来完成一定的内核功能。

这种协同最直观的就是任务间相互通信。

包括VxWorks 等所有的嵌入式操作系统一般都会提供许多任务间通信的方法,通常包括:(1)共享内存,数据的简单共享。

(2)信号量,基本的互斥和同步。

(3)消息队列和管道,同一CPU 内多任务间消息传递。

(4)Socket 和远程调用,任务间透明的网络通信。

(5)Signals,用于异常处理。

在μC/OS-II中设计了五种通讯机制,或者说是同步机制,分别是信号量(semaphore),互斥体(mutual exclusion semaphore),事件组(event flag),邮箱(message box)和队列(queue)。

3. uC/OS-II中通信机制实现的方式分析在uC/OS-II中是如何通信机制呢?这几种通信机制有什么关系?或者说有什么共同点有什么不同点?在实现上有哪些步骤是相同的?下面将就这几个问题进行分析论述。

我们知道通信机制是发生在任务之间的,换句话说任务与通信机制存在着关联。

在内核又是如何处理这种关联呢?通信机制具体来说是信号量,互斥量,邮箱,队列等。

通信机制协调的关系一般是针对两个以上的任务,比如说当两个任务互斥的访问共享资源,就需要一个互斥量,这个互斥量就关联着这两个任务。

同样的道理,其他通信机制也是关联着两个以上的任务。

那么设计内核时就要考虑如何将他们的关系有效协调地统一管理起来。

在内核中是通过一个事件控制块来实现通信机制与任务的联系。

这里所说的事件就是指任务间进行通信时传递信号的统称。

这里其实是利用到了一种抽象的思想,即将各种通信机制的共同点抽象出来,于是内核就设计了一个事件控制块的数据结构,这个数据结构是所有通信机制都会用到的,这样的设计就节省了不少代码,因为有共同点意味着有重复代码。

既然知道了事件控制块是实现通信机制代码共享的关键,那么下面我们就来分析下它的数据结构。

typedef struct{INT8U OSEventType; //事件类型INT8U OSEventGrp; //等待任务所在的组INT16U OSEventCnt; //当事件是信号量时的计数器void *OSEventPtr; //指向消息或消息队列的指针INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; //等待任务列表} OS_EVENT;第一个变量是事件类型,它可以是信号量,互斥型信号量,邮箱或是消息队列中的一种。

OSEventPtr是一个泛型指针,只在所定义的事件是邮箱或者消息队列时才会用到,用来指向一个消息,指针类型设计成泛型的,这是一个设计技巧,因为还不知道具体的消息是什么样的数据结构类型。

OSEventGrp和OSEventTbl[OS_EVENT_TBL_SIZE]用来控制等待某事件的任务,换句话说是等待某事件的任务列表信息。

通过查询这个列表信息可以知道有哪些任务在等待这个事件。

OSEventCnt是计数器,当事件定义的是信号量或者是互斥型信号量时会用到。

从这个事件控制块的数据结构我们可以看出,它是具有抽象性质的,即可以定义成不同的事件类型,可根据具体情况进行不同类型的定义,它具有一定的通用性,又具有一定的针对性(如OSEventPtr只对邮箱或者消息队列有用)。

也就是说这样的设计抽象的程序不够,存在着一定的数据冗余,比如说当事件定义成信号量时,根本用不到OSEventPtr这个变量,它就相当是一个冗余变量,这是内核设计存在的一个缺陷。

下面分析下事件控制块是如何管理其等待的任务。

首先等待一个事件的任务可能是多个,而且任务加入等待列队的时间不一样,那么又如何合理地安排它们的等待顺序呢?在内核中又是如何实现的呢?当一个事件发生后,该事件的等待事件列表中优先级最高的任务得到该任务。

事件等待列表是利用OSEventGrp和OSEventTbl[OS_EVENT_TBL_SIZE]这两个变量来控制的。

在μC/OS-II实时操作系统内核中最多能控制64个任务。

也就是说任务列表必须能表示出64个任务的信息。

在内核中,所有任务优先级被分成8组(每组8个优先级),分别对应于OSEventGrp的8位,这个变量被定义成8位的数据类型,每一位都用来指示是否有任务在等待事件发生的状态。

当某组中有有任务处于等待事件的状态时,OSEventGrp对应的位就会被置1。

相应地,该任务在OSEventTbl[]中对应位也被置1。

那么实现一个任务置于等待事件的任务列表中或者从等待事件的任务列表中使任务脱离等待状态或者在等待事件列表中查找优先级最高的任务的算法又怎么样的呢?将一个任务插入到等待事件的任务列表中:pevent -> OSEventGrp |= OSMapTbl[prio >> 3];pevent -> OSEventTbl[prio>>3] = OSMapTbl[prio & 0x07];从等待事件的任务列表中使任务脱离等待状态:if ((pevent -> OSEventTbl[prio >>3] &= ~OSMapTbl[prio & 0x07]) == 0){pevent -> OSEventGrp &= ~OSMapTbl[prio >>3];}在等待事件的任务列表中查找优先级最高的任务:y = OSUnMapTbl[pevent -> OSEventGrp];x = OSUnMapTbl[pevent -> OSEventTbl[y];prio = (y << 3) + x;从上述代码中可以看到用到了两个数组,一个是OSMapTbl[],一个是OSUnMapTbl[],它们是已经定义的映射表,如OSMapTbl[]的内容是{1,2,4,8,16,32,64,128},这个数组出现的目的是为了更方便的置位。

说白点,使用OSMapTbl[index]的作用是更方便的把某个数值的第index位置1。

从上述的代码中我们可以看出算法的原理是:任务的优先级的最低3位决定了该任务在相应的OSEventTbl[]中的位置,紧接着的高3位则决定了该任务优先级在OSEventTbl[]中的字节索引。

处理事件与任务的关系时需要处理的三个共同问题:使一个任务进入就绪态,使一个任务进入等待某事件发生的状态,由于等待超时而将任务置为就绪态。

分别对应于三个函数。

这样的处理可以避免大量重复的代码,因为这些处理是所有通信机制所必须的,没有必要为每个通信机制就写一个独特的函数来处理。

下面提出一个问题,既然事件控制块是所有通信机制的抽象,那么具体的通信机制又是如何与事件控制块进行关联呢?下面我以信号量的设计为例来进行说明。

创建一个信号量时即要先创建一个事件控制块,在内核中是从事件空闲块中取出一个事件控制块,然后对这个事件控制块的数据变量进行赋值,使之成为表示一个信号量的数据结构。

并将些事件控制块进行初始化,初始化的主要工作是将事件的任务等待列表清空为0。

并把创建好的事件控制块指针返回。

这个返回的事件控制块指针就是一个信号量,等待信号量与发送信号量都是用到这个指针的。

那么某个任务发送一个创建好的信号量又是如何实现的?信号量在创建时会有个计数器,这个计数器标志着可用资源数,创建信号量时可以初始为0。

当一个任务发送一个信号量时,需要考虑几个问题:发送的信号量是否真的存在?有没有任务在等待这个信号量?信号量的计数器值有没有超过范围?当发送的信号不存在时或者信号量的计数器的值超过范围要直接返回一个错误代码。

如果有任务在等待这个信号量,那么就让这个任务等待列表中最高优先级的任务马上进入就绪态准备运行。

计数器不用加1,因为资源已经消耗了(有任务得到信号量进入就绪态)。

如果没有任务在等待这个信号量,那么计数个器值加1,表示又多一个信号量可用。

而任务等待一个信号量的实现方式又是如何设计的呢?内核支持超时等待机制,即可以限定等待的时间,在限定的时间内没有收到信号量时任务会自动进入就绪态准备运行。

等待一个信号量本质上就判断一个信号量的计数值是否大于0,如果大于0说明信号量可用,等待的信号量已经到达,任务可以执行后面的程序,然后还要把计数值减1,表示消耗了一个信号量。

如果计数值为0(等待的信号量还没有到),那么任务要进入休眠态,实现的方法是将限定等待的时间值任务赋给任务的延时值。

任务控制块的数据结构中有一个变量是延时值,用来控制休眠的时间,改变这个延时值就相当于是改变这个任务的休眠时间,一般处于就绪态的任务延时值是为0的。

任务进入就绪态后就重新进行任务的调度。

当这个任务从休眠态回复到运行态时有两种可能:一种是超时了,一种是在限定的时间内得到了一个信号量,那么在恢复运行态时就要进行一个判断。

那现在提出一个问题是:如何区分这两种情况呢?内核是作何处理的呢?原来任务控制块中有一个变量是状态变量,这个变量标志着任务是处于何种状态,是在等待一个信号量还是在已经得到了一个信号量。

任务在休眠前这个变量表示的是任务处于等待一个信号量的状态。

如果等待超时后还没有得到信号量,那么这个状态变量是没有发生变化的,任务恢复运行时可以判断这个变量,如果表示处于等待一个信号量的状态,那么就意味着等待超时了,则任务就要进入就绪态准备运行。

如果任务在进入休眠态期间,有其他任务释放信号量时,就会发现有任务在等待这个信号量,并将这个任务处于就绪态准备运行,同时改变这个任务的状态变量,让它表示这个任务已经得到信号量了。

任务恢复运行时就会知道是得到了信号量,然后可以处理后面的内容。

通过以上分析我们可以很清楚的知道事件控制块是如何与具体的通信机制进行了结合。

相关文档
最新文档